What are the differences between a+i and &a[i] for pointer arithmetic in C++?Does the 'offsetof' macro...
What is this metal M-shaped device for?
How do you funnel food off a cutting board?
Can I string the D&D Starter Set campaign into another module, keeping the same characters?
How would an AI self awareness kill switch work?
If I delete my router's history can my ISP still provide it to my parents?
Publishing research using outdated methods
One Half of Ten; A Riddle
What is the wife of a henpecked husband called?
Am I a Rude Number?
What are the differences between a+i and &a[i] for pointer arithmetic in C++?
Why did other German political parties disband so fast when Hitler was appointed chancellor?
Avoiding morning and evening handshakes
Difference between `vector<int> v;` and `vector<int> v = vector<int>();`
Why "Points exist" is not an axiom in Geometry
Why avoid shared user accounts?
What happens to output if OPAMP its supply is tweaked?
Program that converts a number to a letter of the alphabet
Intern applicant asking for compensation equivalent to that of permanent employee
We are very unlucky in my court
What are "industrial chops"?
It took me a lot of time to make this, pls like. (YouTube Comments #1)
In Linux what happens if 1000 files in a directory are moved to another location while another 300 files were added to the source directory?
What's a good word to describe a public place that looks like it wouldn't be rough?
Dilemma of explaining to interviewer that he is the reason for declining second interview
What are the differences between a+i and &a[i] for pointer arithmetic in C++?
Does the 'offsetof' macro from <stddef.h> invoke undefined behaviour?The nullptr and pointer arithmeticWhat is the difference between #include <filename> and #include “filename”?What are the differences between a pointer variable and a reference variable in C++?What is a smart pointer and when should I use one?What is the difference between g++ and gcc?Difference between 'struct' and 'typedef struct' in C++?What is the effect of extern “C” in C++?What is the difference between const int*, const int * const, and int const *?What is the “-->” operator in C++?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?What is the difference between 'typedef' and 'using' in C++11?
Supposing we have:
char* a;
int i;
Many introductions to C++ (like this one) suggest that the rvalues a+i
and &a[i]
are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:
in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.
In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i]
(within the offsetof
macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i]
causes undefined behavior in the case where a=null
and i=0
. This behavior is different from a+i
(at least in C++, in the a=null, i=0 case).
This leads to at least 2 questions about the differences between a+i
and &a[i]
:
First, what is the underlying semantic difference between a+i
and &a[i]
that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i]
might generate a memory access to a[i]
? Or the spec author wasn't happy with null dereferences that day? Or something else?
Second, besides the case where a=null
and i=0
, are there any other cases where a+i
and &a[i]
behave differently? (could be covered by the first question, depending on the answer to it.)
c++ language-lawyer pointer-arithmetic
|
show 5 more comments
Supposing we have:
char* a;
int i;
Many introductions to C++ (like this one) suggest that the rvalues a+i
and &a[i]
are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:
in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.
In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i]
(within the offsetof
macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i]
causes undefined behavior in the case where a=null
and i=0
. This behavior is different from a+i
(at least in C++, in the a=null, i=0 case).
This leads to at least 2 questions about the differences between a+i
and &a[i]
:
First, what is the underlying semantic difference between a+i
and &a[i]
that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i]
might generate a memory access to a[i]
? Or the spec author wasn't happy with null dereferences that day? Or something else?
Second, besides the case where a=null
and i=0
, are there any other cases where a+i
and &a[i]
behave differently? (could be covered by the first question, depending on the answer to it.)
c++ language-lawyer pointer-arithmetic
You may want to add "language-lawyer" tag to this.
– P.W
3 hours ago
@P.W good idea. Done.
– personal_cloud
3 hours ago
according to the answers here,a+i
is undefined ifa=null
, though your 4th link says it is defined ifi=0
, hmmm
– kmdreko
3 hours ago
@kmdreko. That's a good point. I've tweaked the difference description to focus on thea=null
,i=0
case for establishing that there is a difference betweena+i
and&a[i]
... Again, leading one to wonder if there are any other differences between them.
– personal_cloud
3 hours ago
2
The intent of the standard never was to disallow&*a
whena
is a null pointer. This is a subject of issue 232.
– n.m.
3 hours ago
|
show 5 more comments
Supposing we have:
char* a;
int i;
Many introductions to C++ (like this one) suggest that the rvalues a+i
and &a[i]
are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:
in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.
In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i]
(within the offsetof
macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i]
causes undefined behavior in the case where a=null
and i=0
. This behavior is different from a+i
(at least in C++, in the a=null, i=0 case).
This leads to at least 2 questions about the differences between a+i
and &a[i]
:
First, what is the underlying semantic difference between a+i
and &a[i]
that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i]
might generate a memory access to a[i]
? Or the spec author wasn't happy with null dereferences that day? Or something else?
Second, besides the case where a=null
and i=0
, are there any other cases where a+i
and &a[i]
behave differently? (could be covered by the first question, depending on the answer to it.)
c++ language-lawyer pointer-arithmetic
Supposing we have:
char* a;
int i;
Many introductions to C++ (like this one) suggest that the rvalues a+i
and &a[i]
are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:
in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.
In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i]
(within the offsetof
macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i]
causes undefined behavior in the case where a=null
and i=0
. This behavior is different from a+i
(at least in C++, in the a=null, i=0 case).
This leads to at least 2 questions about the differences between a+i
and &a[i]
:
First, what is the underlying semantic difference between a+i
and &a[i]
that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i]
might generate a memory access to a[i]
? Or the spec author wasn't happy with null dereferences that day? Or something else?
Second, besides the case where a=null
and i=0
, are there any other cases where a+i
and &a[i]
behave differently? (could be covered by the first question, depending on the answer to it.)
c++ language-lawyer pointer-arithmetic
c++ language-lawyer pointer-arithmetic
edited 2 hours ago
personal_cloud
asked 3 hours ago
personal_cloudpersonal_cloud
826615
826615
You may want to add "language-lawyer" tag to this.
– P.W
3 hours ago
@P.W good idea. Done.
– personal_cloud
3 hours ago
according to the answers here,a+i
is undefined ifa=null
, though your 4th link says it is defined ifi=0
, hmmm
– kmdreko
3 hours ago
@kmdreko. That's a good point. I've tweaked the difference description to focus on thea=null
,i=0
case for establishing that there is a difference betweena+i
and&a[i]
... Again, leading one to wonder if there are any other differences between them.
– personal_cloud
3 hours ago
2
The intent of the standard never was to disallow&*a
whena
is a null pointer. This is a subject of issue 232.
– n.m.
3 hours ago
|
show 5 more comments
You may want to add "language-lawyer" tag to this.
– P.W
3 hours ago
@P.W good idea. Done.
– personal_cloud
3 hours ago
according to the answers here,a+i
is undefined ifa=null
, though your 4th link says it is defined ifi=0
, hmmm
– kmdreko
3 hours ago
@kmdreko. That's a good point. I've tweaked the difference description to focus on thea=null
,i=0
case for establishing that there is a difference betweena+i
and&a[i]
... Again, leading one to wonder if there are any other differences between them.
– personal_cloud
3 hours ago
2
The intent of the standard never was to disallow&*a
whena
is a null pointer. This is a subject of issue 232.
– n.m.
3 hours ago
You may want to add "language-lawyer" tag to this.
– P.W
3 hours ago
You may want to add "language-lawyer" tag to this.
– P.W
3 hours ago
@P.W good idea. Done.
– personal_cloud
3 hours ago
@P.W good idea. Done.
– personal_cloud
3 hours ago
according to the answers here,
a+i
is undefined if a=null
, though your 4th link says it is defined if i=0
, hmmm– kmdreko
3 hours ago
according to the answers here,
a+i
is undefined if a=null
, though your 4th link says it is defined if i=0
, hmmm– kmdreko
3 hours ago
@kmdreko. That's a good point. I've tweaked the difference description to focus on the
a=null
, i=0
case for establishing that there is a difference between a+i
and &a[i]
... Again, leading one to wonder if there are any other differences between them.– personal_cloud
3 hours ago
@kmdreko. That's a good point. I've tweaked the difference description to focus on the
a=null
, i=0
case for establishing that there is a difference between a+i
and &a[i]
... Again, leading one to wonder if there are any other differences between them.– personal_cloud
3 hours ago
2
2
The intent of the standard never was to disallow
&*a
when a
is a null pointer. This is a subject of issue 232.– n.m.
3 hours ago
The intent of the standard never was to disallow
&*a
when a
is a null pointer. This is a subject of issue 232.– n.m.
3 hours ago
|
show 5 more comments
2 Answers
2
active
oldest
votes
TL;DR: a+i
and &a[i]
are both well-formed and produce a null pointer when a
is a null pointer and i
is 0, according to (the intent of) the standard, and all compilers agree.
a+i
is obviously well-formed per [expr.add]/4 of the latest draft standard:
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
- If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
- [...]
&a[i]
is tricky. Per [expr.sub]/1, a[i]
is equivalent to *(a+i)
, thus &a[i]
is equivalent to &*(a+i)
. Now the standard is not quite clear about whether &*(a+i)
is well-formed when a+i
is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.
Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.
Here's the demo, if the compilers think the constant expression in static_assert
is UB, or if they think the result is not true
, then they must produce a diagnostic (error or warning) per standard:
(note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return a+i;
}());
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return &a[i];
}());
From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).
However, this is different from the offset
case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&
), and thus is subject to the requirements on references.
add a comment |
In the C++ standard, section [expr.sub]/1 you can read:
The expression
E1[E2]
is identical (by definition) to*((E1)+(E2))
.
This means that &a[i]
is exactly the same as &*(a+i)
. So you would dereference *
a pointer first and get the address &
second. In case the pointer is invalid (i.e. nullptr
, but also out of range), this is UB.
a+i
is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:
When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
expression P points to element x[i] of an array object x with n
elements, the expressions P + J and J + P (where J has the value j)
point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
n; otherwise, the behavior is undefined. Likewise, the expression P -
J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
≤ n; otherwise, the behavior is undefined.
So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
1 hour ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54938610%2fwhat-are-the-differences-between-ai-and-ai-for-pointer-arithmetic-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
TL;DR: a+i
and &a[i]
are both well-formed and produce a null pointer when a
is a null pointer and i
is 0, according to (the intent of) the standard, and all compilers agree.
a+i
is obviously well-formed per [expr.add]/4 of the latest draft standard:
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
- If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
- [...]
&a[i]
is tricky. Per [expr.sub]/1, a[i]
is equivalent to *(a+i)
, thus &a[i]
is equivalent to &*(a+i)
. Now the standard is not quite clear about whether &*(a+i)
is well-formed when a+i
is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.
Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.
Here's the demo, if the compilers think the constant expression in static_assert
is UB, or if they think the result is not true
, then they must produce a diagnostic (error or warning) per standard:
(note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return a+i;
}());
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return &a[i];
}());
From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).
However, this is different from the offset
case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&
), and thus is subject to the requirements on references.
add a comment |
TL;DR: a+i
and &a[i]
are both well-formed and produce a null pointer when a
is a null pointer and i
is 0, according to (the intent of) the standard, and all compilers agree.
a+i
is obviously well-formed per [expr.add]/4 of the latest draft standard:
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
- If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
- [...]
&a[i]
is tricky. Per [expr.sub]/1, a[i]
is equivalent to *(a+i)
, thus &a[i]
is equivalent to &*(a+i)
. Now the standard is not quite clear about whether &*(a+i)
is well-formed when a+i
is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.
Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.
Here's the demo, if the compilers think the constant expression in static_assert
is UB, or if they think the result is not true
, then they must produce a diagnostic (error or warning) per standard:
(note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return a+i;
}());
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return &a[i];
}());
From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).
However, this is different from the offset
case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&
), and thus is subject to the requirements on references.
add a comment |
TL;DR: a+i
and &a[i]
are both well-formed and produce a null pointer when a
is a null pointer and i
is 0, according to (the intent of) the standard, and all compilers agree.
a+i
is obviously well-formed per [expr.add]/4 of the latest draft standard:
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
- If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
- [...]
&a[i]
is tricky. Per [expr.sub]/1, a[i]
is equivalent to *(a+i)
, thus &a[i]
is equivalent to &*(a+i)
. Now the standard is not quite clear about whether &*(a+i)
is well-formed when a+i
is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.
Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.
Here's the demo, if the compilers think the constant expression in static_assert
is UB, or if they think the result is not true
, then they must produce a diagnostic (error or warning) per standard:
(note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return a+i;
}());
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return &a[i];
}());
From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).
However, this is different from the offset
case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&
), and thus is subject to the requirements on references.
TL;DR: a+i
and &a[i]
are both well-formed and produce a null pointer when a
is a null pointer and i
is 0, according to (the intent of) the standard, and all compilers agree.
a+i
is obviously well-formed per [expr.add]/4 of the latest draft standard:
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
- If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
- [...]
&a[i]
is tricky. Per [expr.sub]/1, a[i]
is equivalent to *(a+i)
, thus &a[i]
is equivalent to &*(a+i)
. Now the standard is not quite clear about whether &*(a+i)
is well-formed when a+i
is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.
Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.
Here's the demo, if the compilers think the constant expression in static_assert
is UB, or if they think the result is not true
, then they must produce a diagnostic (error or warning) per standard:
(note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return a+i;
}());
static_assert(nullptr == [](char* a=nullptr, int i=0) {
return &a[i];
}());
From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).
However, this is different from the offset
case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&
), and thus is subject to the requirements on references.
edited 20 mins ago
answered 1 hour ago
cpplearnercpplearner
5,16521937
5,16521937
add a comment |
add a comment |
In the C++ standard, section [expr.sub]/1 you can read:
The expression
E1[E2]
is identical (by definition) to*((E1)+(E2))
.
This means that &a[i]
is exactly the same as &*(a+i)
. So you would dereference *
a pointer first and get the address &
second. In case the pointer is invalid (i.e. nullptr
, but also out of range), this is UB.
a+i
is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:
When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
expression P points to element x[i] of an array object x with n
elements, the expressions P + J and J + P (where J has the value j)
point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
n; otherwise, the behavior is undefined. Likewise, the expression P -
J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
≤ n; otherwise, the behavior is undefined.
So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
1 hour ago
add a comment |
In the C++ standard, section [expr.sub]/1 you can read:
The expression
E1[E2]
is identical (by definition) to*((E1)+(E2))
.
This means that &a[i]
is exactly the same as &*(a+i)
. So you would dereference *
a pointer first and get the address &
second. In case the pointer is invalid (i.e. nullptr
, but also out of range), this is UB.
a+i
is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:
When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
expression P points to element x[i] of an array object x with n
elements, the expressions P + J and J + P (where J has the value j)
point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
n; otherwise, the behavior is undefined. Likewise, the expression P -
J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
≤ n; otherwise, the behavior is undefined.
So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
1 hour ago
add a comment |
In the C++ standard, section [expr.sub]/1 you can read:
The expression
E1[E2]
is identical (by definition) to*((E1)+(E2))
.
This means that &a[i]
is exactly the same as &*(a+i)
. So you would dereference *
a pointer first and get the address &
second. In case the pointer is invalid (i.e. nullptr
, but also out of range), this is UB.
a+i
is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:
When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
expression P points to element x[i] of an array object x with n
elements, the expressions P + J and J + P (where J has the value j)
point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
n; otherwise, the behavior is undefined. Likewise, the expression P -
J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
≤ n; otherwise, the behavior is undefined.
So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.
In the C++ standard, section [expr.sub]/1 you can read:
The expression
E1[E2]
is identical (by definition) to*((E1)+(E2))
.
This means that &a[i]
is exactly the same as &*(a+i)
. So you would dereference *
a pointer first and get the address &
second. In case the pointer is invalid (i.e. nullptr
, but also out of range), this is UB.
a+i
is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:
When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
expression P points to element x[i] of an array object x with n
elements, the expressions P + J and J + P (where J has the value j)
point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
n; otherwise, the behavior is undefined. Likewise, the expression P -
J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
≤ n; otherwise, the behavior is undefined.
So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.
answered 2 hours ago
ChristopheChristophe
40.3k43576
40.3k43576
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
1 hour ago
add a comment |
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
1 hour ago
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
1 hour ago
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
1 hour ago
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54938610%2fwhat-are-the-differences-between-ai-and-ai-for-pointer-arithmetic-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
You may want to add "language-lawyer" tag to this.
– P.W
3 hours ago
@P.W good idea. Done.
– personal_cloud
3 hours ago
according to the answers here,
a+i
is undefined ifa=null
, though your 4th link says it is defined ifi=0
, hmmm– kmdreko
3 hours ago
@kmdreko. That's a good point. I've tweaked the difference description to focus on the
a=null
,i=0
case for establishing that there is a difference betweena+i
and&a[i]
... Again, leading one to wonder if there are any other differences between them.– personal_cloud
3 hours ago
2
The intent of the standard never was to disallow
&*a
whena
is a null pointer. This is a subject of issue 232.– n.m.
3 hours ago