Question

I realized, what if i define const int into the body of c++ function and then use the address arithmetic to change the value of the constant( its on the stack, isn't it? ). i got this code:

const int a = 10;
int b = 100;

int * c = &b;
c++;

cout << "&a: " << &a << endl;
cout << " c: " << c << endl;


*c = 100500;

cout << " a: " << a << endl;
cout << "*c: " << *c << endl;

and i got this output

&a: 0x7ffff63866a8
c: 0x7ffff63866a8

 a: 10
*c: 100500

So, addresses are the same, but values are different. Can someone explain me this result? Thanks! p.s. i tried on GCC, Clang and VS

Was it helpful?

Solution 3

const int a = 10;
int b = 100;

OK.

int * c = &b;

OK, but silly and my bug-o-meter is starting to twiddle.

c++;

Bug-o-meter now in the yellow zone.

cout << "&a: " << &a << endl;

OK

*c = 100500;

Bug-o-meter pegged. Undefined Behavior invoked. World explodes, you get fired.

c++ moves the pointer to the next int in memory. The pointer math is OK, but all you can use c for at this point is to compare the pointer to another pointer. You can't dereference the pointer in any way. But that's what you do when you try to assign through it.

What happens next is irrelevant and, honestly, misleading. You think that c now points to the same memory as b, and maybe it does. But it's only through Undefined Behavior that this happened. You might also think that the value of *c is what you expect it to be, but this result is false. Maybe it is, maybe it isn't. You shattered the vial when you opened the box -- the cat is dead. And so is your program.

And by the way, if what you're trying to do is find a way to cheat the compiler so that you can change a const, don't -- it is strictly forbidden to change a const by any means.

There is a const_cast in C++, but that is also not a mechanism that you can use to change a const.

OTHER TIPS

Can someone explain me this result?

As with any attempt to access objects in invalid ways via invalid pointer arithmetic or other shenanigans: undefined behaviour.

What is happening here is that the compiler is assuming that the value of a won't change, and optimising it to be a compile-time constant. It's allowed to do that, since you've declared it const and thereby stated that it won't change.

its on the stack, isn't it?

Since you also take the address of it (when you print &a), it does get allocated an address on the stack; but there's no need for the program to read from that address to get the value, since it's already known to be 10.

Of course, this is all undefined, so the program would be just as valid if it ordered you a pizza instead.

Your program has undefined behavior written all over it...

The assumption that incrementing the address of b will get you to a is bogus, it could or it could not. You are then using what is called in the standard unsafely derived pointer to modify a const object (a) which is also undefined behavior. Anything can happen.

What really happens (in your implementation, explanation of your results but you cannot depend on this as this is undefined behavior) is that you forced the allocation of a in the stack by means of taking its address, and you got a pointer into it. You modified that value, and the address in memory is updated. But, in the expression: cout << " a: " << a << endl; the compiler knows that a is a constant, and thus its value can only be 10, so it transformed the code into cout << " a: " << 10 << endl; to avoid having to go to memory to obtain the value.

its on the stack, isn't it?

No, your expectations are wrong. C++ has no notion of stack whatsoever, much less of how different automatic variables are stored in memory relative to each other. What you are trying to do is plain Undefined Behaviour.

In your very case, the compilers optimize a away, because they are allowed to by the standard, and the results you're getting don't have to make any sense since it's UB anyway.

The C++ compiler will simply assume that you will never try to change the value of a const variable.

This doesn't mean that if you do you will get an error... just that the compiler authors can ignore what is going to happen and anything that happens will be classified as "your fault".

SSCC:

#include <stdio.h>

int main ()
{
  const int a = 10;
  int b = 100;
  int *c = &b;
  printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
    a, b, *c, (void *)&a, (void *)&b, (void *)c);

  c++;  // "c" now invalid
  printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
    a, b, *c, (void *)&a, (void *)&b, (void *)c);

  *c = 100500;  // Undefined behavior!
  printf ("a=%d, b=%d, *c=%d; &a=%p, &b=%p, c=%p\n",
    a, b, *c, (void *)&a, (void *)&b, (void *)c);

  return 0;
}

EXAMPLE OUTPUT:

a=10, b=100, *c=100; &a=0028FF18, &b=0028FF14, c=0028FF14
a=10, b=100, *c=10; &a=0028FF18, &b=0028FF14, c=0028FF18
a=10, b=100, *c=100500; &a=0028FF18, &b=0028FF14, c=0028FF18

CASE 2 - WE DON'T TRY TO TAKE ADDRESSOF CONST A:

#include <stdio.h>

int main ()
{
  const int a = 10;
  int b = 100;
  int *c = &b;
  printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
    a, b, *c, (void *)&b, (void *)c);

  c++;  // "c" now invalid
  printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
    a, b, *c, (void *)&b, (void *)c);

  *c = 100500;  // Undefined behavior!
  printf ("a=%d, b=%d, *c=%d; &b=%p, c=%p\n",
    a, b, *c, (void *)&b, (void *)c);

  return 0;
}

SAMPLE OUTPUT

a=10, b=100, *c=100; &b=0028FF14, c=0028FF14
a=10, b=100, *c=2686744; &b=0028FF14, c=0028FF18
a=10, b=100, *c=0; &b=0028FF14, c=00018894
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top