What are the differences between a+i and &a[i] for pointer arithmetic in C++?Does the 'offsetof' macro...
Why is working on the same position for more than 15 years not a red flag?
What is the wife of a henpecked husband called?
Intern applicant asking for compensation equivalent to that of permanent employee
Blindfold battle as a gladiatorial spectacle - what are the tactics and communication methods?
How to say "Brexit" in Latin?
Is there any other number that has similar properties as 21?
Why do stocks necessarily drop during a recession?
Can a hotel cancel a confirmed reservation?
Porting Linux to another platform requirements
If I delete my router's history can my ISP still provide it to my parents?
How to escape the null character in here-document?(bash and/or dash)
It took me a lot of time to make this, pls like. (YouTube Comments #1)
Why did other German political parties disband so fast when Hitler was appointed chancellor?
Can a person refuse a presidential pardon?
Why exactly do action photographers need high fps burst cameras?
Difference between `vector<int> v;` and `vector<int> v = vector<int>();`
Why do no American passenger airlines still operate dedicated cargo flights?
Is there any differences between "Gucken" and "Schauen"?
Who is this Ant Woman character in this image alongside the Wasp?
A starship is travelling at 0.9c and collides with a small rock. Will it leave a clean hole through, or will more happen?
How do Chazal know that the descendants of a Mamzer may never marry into the general populace?
Cookies - Should the toggles be on?
What is 6÷2×(1+2) =?
Early credit roll before the end of the film
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
4 hours ago
@P.W good idea. Done.
– personal_cloud
4 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
4 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
4 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.
4 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 3 hours ago
personal_cloud
asked 4 hours ago
personal_cloudpersonal_cloud
826615
826615
You may want to add "language-lawyer" tag to this.
– P.W
4 hours ago
@P.W good idea. Done.
– personal_cloud
4 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
4 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
4 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.
4 hours ago
|
show 5 more comments
You may want to add "language-lawyer" tag to this.
– P.W
4 hours ago
@P.W good idea. Done.
– personal_cloud
4 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
4 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
4 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.
4 hours ago
You may want to add "language-lawyer" tag to this.
– P.W
4 hours ago
You may want to add "language-lawyer" tag to this.
– P.W
4 hours ago
@P.W good idea. Done.
– personal_cloud
4 hours ago
@P.W good idea. Done.
– personal_cloud
4 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
4 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
4 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
4 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
4 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.
4 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.
4 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
2 hours 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 1 hour ago
answered 2 hours ago
cpplearnercpplearner
5,17521937
5,17521937
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
2 hours 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
2 hours 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
2 hours ago
add a comment |
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
2 hours ago
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
2 hours ago
But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.
– cpplearner
2 hours 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
4 hours ago
@P.W good idea. Done.
– personal_cloud
4 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
4 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
4 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.
4 hours ago