Reputation: 6118
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
Upvotes: 7
Views: 377
Reputation: 33252
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.
Upvotes: 1
Reputation: 19721
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).
Upvotes: 0
Reputation: 370112
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.
Upvotes: 15
Reputation: 471229
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.
Upvotes: 2
Reputation: 84159
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
).
Upvotes: 2