7

I was asked how can a value of a const variable can be changed.

My my obvious answer was "pointers!" but I tried the next piece of code and I'm puzzled...

int main()
{
    const int x = 5;
    int *ptr = (int *)(&x); // "Cast away" the const-ness..
    cout << "Value at " << ptr << ":"<< (*ptr) <<endl;
    *ptr = 6;
    cout << "Now the value of "<< ptr << " is: " << (*ptr) <<endl;
    cout << "But the value of x is still " << x <<endl;
    return 0;
}

And the output was:

Value at <some address> :5
Now the value of <same address> is: 6
But the value of x is still 5

Now, I'm not sure exactly what is returned from '&x' but it's definitely not the actual address of x, since the value at x wasn't changed!

But on the over hand, ptr did contain the value of x at the beginning! So, what is it exactly?

EDIT compiled with VS2010

Makoto
  • 104,088
  • 27
  • 192
  • 230
Avi Shukron
  • 6,088
  • 8
  • 50
  • 84
  • 2
    looks like an "optimization" to me - the `x` probably just gets replaced by `5` wherever possible. Does the same thing happen in debug mode? – Ken Wayne VanderLinde Nov 13 '11 at 22:08
  • 9
    Do you realize that the behaviour is undefined and no explanation will be accurate across implementations? –  Nov 13 '11 at 22:08
  • Imagine if you did `#define X 5`. Also, hopefully needless to say except for a puzzle...um... the way to change a const is to remove "const". – mike jones Nov 13 '11 at 22:11
  • but you did not answer the question! what is the result of & on a #define macro?? – Avi Shukron Nov 13 '11 at 22:12
  • @mike: If he did `#define X 5`, writing `&X` would cause a compiler error. – sepp2k Nov 13 '11 at 22:12
  • Dupe, dupe, dupe: [changing the value of const variable in C++](http://stackoverflow.com/questions/2006161/changing-the-value-of-const-variable-in-c) (Not that it's bad to post a dupe.) – Chris Lutz Nov 13 '11 at 22:13
  • add `static` to your declaration of `x` and you'll probably get a segfault... – Christoph Nov 13 '11 at 22:14
  • @ChrisLutz - Sorry man, I did search first - but for expressions like "reference operator on const" and that question didn't came up. But you are right. It is a duplicate. – Avi Shukron Nov 13 '11 at 22:32
  • I tried the same test with g++ and gcc and the result is different: with gcc, the value of `x` changes. This is probably due to the different role of const in c++ and c: http://stackoverflow.com/questions/5248571/is-there-const-in-c/5248645#5248645 – stardt Nov 13 '11 at 22:36

5 Answers5

15

Your program invokes undefined behavior (writing to a const variable through a pointer is undefined behavior), so anything might happen. That being said here's the most likely explanation why you get the behavior you see on your particular implementation:

When you do &x, you do get the address of x. When you do *ptr = 6, you do write 6 to x's memory location. However when you do cout << x, you don't actually read from x's memory location because your compiler optimized the code by replacing x with 5 here. Since x is const the compiler is allowed to do that since there is no legal C++ program in which doing so would change the program's behavior.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
2

Compiler caches x in a register, so the value in memory changes, but the last print-out is still the same. Check out generated assembly (compile with -s).

Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
  • 1
    It doesn't need to cache it in a register. Since `x` was declared `const`, it can simply replace `cout << x` with (the equivalent of) `cout << 5` -- or even `cout << "5"` or `cout << '5'`. – Keith Thompson Nov 13 '11 at 22:29
2

First of all, this behavior is undefined. That said, here's what's probably going on:

When you do this:

int *ptr = (int *)(&x);

The 5 is stored at some address at somewhere. That's why the pointer seems to work properly. (although casting away the const is still undefined behavior)

However, due to compiler optimizations x = 5 is just inlined as a literal in the final print statement. The compiler thinks it's safe because x is declared const.

cout << "But the value of x is still " << x <<endl;

That's why you print out the original value 5.

Mysticial
  • 464,885
  • 45
  • 335
  • 332
1

Maybe you are experiencing a side effect of code optimization, try to run the same code by disabling all optimization, or check at the asm generated code. I guess the compiler is reusing the value it has in some registry along the function since he bet on the const, so even if you are actually changing the value, the changed value is not propagated properly. The reasons for that as Keith noticed in the comemnts, is that you are palying with an undefined behavior.

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
  • How do I disable optimization on VS2010? It's likely that you were right. – Avi Shukron Nov 13 '11 at 22:26
  • 1
    It isn't necessarily possible to disable *all* optimization. A compiler is not obligated to provide a mode in which referring to `x` actually retrieves whatever is stored in memory at `x`'s address. The program's behavior is undefined; don't waste your time trying to make it do what you want it to do. If you wanted to change `x`, you shouldn't have made it `const`! – Keith Thompson Nov 13 '11 at 22:30
  • I've been asked in an interview for an idea about how to change const... that's all :) I'm not a ninja... – Avi Shukron Nov 13 '11 at 22:34
  • @Avrahamshuk: Knowing how to change a variable that was declared `const` is useful mostly for tracking down bugs. If a `const`-declared objects' value appears to be changing, it can be useful to know what might have caused it -- so you can fix the bug. (In some very rare cases, it might make some sense to do it deliberately, if it's impractical for some reason to change the variable's definition. But as you've seen, optimizations can defeat such attempts. ["If you lie to the compiler, it will get its revenge."](http://www.lysator.liu.se/c/henry/). – Keith Thompson Nov 13 '11 at 22:58
0

What is returned from &x is a pointer to const int (i.e. int const*). Now pointers are inded implemented as holding the address, but pointers are not addresses, and your example shows quite nicely why: The type of the pointer, even though not present at run time, still plays an important role.

In your case, you are casting away the const, and thus lying to the compiler "this pointer points to a non-const int". However the compiler knows from the declaration that the value of x cannot change (it was declared const), and makes freely use of that fact (and the standard allows it: Your attempt to change it through a pointer to non-const int is undefined behaviour and therefore the compiler is allowed to do anything).

celtschk
  • 19,311
  • 3
  • 39
  • 64