nunojpg
nunojpg

Reputation: 505

Pointer arithmetic ignored by the compiler

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

Answers (2)

user6409912
user6409912

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

NathanOliver
NathanOliver

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

Related Questions