Reputation: 505
I'm compiling the following with -O0 (recent gcc/clang) and they both give me a answer I don't expect.
#include <iostream>
struct xy{
int x,y;
};
int main()
{
xy a{1,2};
int x{1};
int y{2};
int *ptr1=&a.x;
int *ptr2=&x;
ptr1++; // I now point to a.y!
(*ptr1)++; // I now incremented a.y to 3
ptr2++; // I now point to y!
(*ptr2)++; // I now incremented y to 3
std::cout << "a.y=" << a.y << " ptr1=" << *ptr1 << '\n';
std::cout << "y= " << y << " ptr2=" << *ptr2 << '\n';
}
Output:
a.y=3 ptr1=3
y= 2 ptr2=2
So this access with pointers to non-class variables is being optimized-out by the compiler.
I also tried to mark the int and int* as volatile, but it didn't make any difference.
What part of the standard am I missing / why is the compiler allowed to do this?
Coliru snippet at: http://coliru.stacked-crooked.com/a/ed0757a6621c37a9
Upvotes: 0
Views: 190
Reputation:
Pointer arithmetic is only valid in arrays. You cannot reach y
by incementing a pointer to x
. The behaviour of your program is undefined. Your statement
ptr1++; // I now point to a.y!
is simply wrong. Remember that a compiler is allowed to insert an arbitrary amount of padding between the elements in your struct
.
In more detail, you can set a pointer to one past the address of a scalar, but you are not allowed to dereference it.
Upvotes: 3
Reputation: 180935
In the first case dealing with class members the part you are ignoring is the compiler is allowed to add any amount of padding in between members of a object and at the end of the object. Because of this increment a pointer to one member does not have to give you the next member.
The second part of the standard you are missing is it is illegal to access memory though a pointer to what it doesn't point to. Even though y
might be there in memory the pointer is not allowed to access it. It is allowed to access x
and it is allowed to compare to see if it one past x
but it cannot dereference that one past x
address.
Upvotes: 4