1

In the example below, 'ptr' points to the constant variable 'local'. Why does modifying 'local' by assigning '*ptr' not change the value of 'local'?

#include <stdio.h>
int main(void)
{
    const int local = 10;
    int *ptr = (int*) &local;

    printf("address of local: %p \n", &local);
    printf("value of ptr: %p \n", ptr);
    printf("Initial value of local : %d \n", local);
    printf("Initial value of *ptr : %d \n", *ptr);

    *ptr = 100;
    //*((int*)&local) = 1000;

    printf("Modified value of local: %d \n", local);
    printf("Modified value of *ptr: %d \n", *ptr);
    printf("address of local: %p \n", &local);
    printf("value of ptr: %p \n", &(*ptr));

    return 0;
}

The output:

address of local: 0x7ffd946bd9c4
value of ptr: 0x7ffd946bd9c4
Initial value of local : 10 
Initial value of *ptr : 10 
Modified value of local: 10 
Modified value of *ptr: 100 
address of local: 0x7ffd946bd9c4 
value of ptr: 0x7ffd946bd9c4
Toby Speight
  • 23,550
  • 47
  • 57
  • 84
He Chen
  • 13
  • 2
  • 3
    Because it is undefined behavior to cast away `const` of a toplevel `const` object. – nwp Aug 22 '17 at 16:19
  • 3
    @nwp Actually, that's not quite true, the cast itself is not UB. It's only UB to actually modify. In general it's rarely the case (I'm sure there are exceptions) that pointer casts in C++ directly cause UB. It's usually the *usage* of an improperly cast pointer that's UB. – Nir Friedman Aug 22 '17 at 16:21
  • 1
    If you say something is const, it's up to the compiler on how it deals with it. For all you know, it's been put somewhere in read only memory, because you said you wouldn't change it. Now you're trying edit it. Why would you expect it to change? – UKMonkey Aug 22 '17 at 16:22
  • 1
    const in many cases can have NOT address at all (direct value 10 is used in machine code) – Jacek Cz Aug 22 '17 at 16:22
  • Thank you all :). Now I understand it. – He Chen Aug 22 '17 at 16:37
  • It's just as wrong in C, if you were wondering. Or if you use a reference instead of a pointer. – Toby Speight Aug 22 '17 at 16:42
  • Seems like this question is becoming almost as popular as [`i = i++ + ++i;`](https://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior). – Bo Persson Aug 22 '17 at 17:03

2 Answers2

3

The line:

*ptr = 100;

is undefined behavior. The reason why is because ptr points to a const object. You made this compile by casting away the const-ness, but the language still says that actually modifying an object declared const is illegal: http://en.cppreference.com/w/cpp/language/const_cast.

The presence of undefined behavior basically means that your program could do many different, weird things on different compilers/optimization levels. In short, do not modify const objects, and for now steer clear of const_cast. It's usually a sign of bad design; there are relatively few legitimate uses for it which you'll learn as you go. Here's a link to an example of a rare valid use of const_cast: How do I remove code duplication between similar const and non-const member functions?. This technique removes code duplication, but fundamentally it relies on throwing away const-ness when only the pointer is const qualified, but the underlying object is known to not be const.

The difference between actual const values, and a const aliasing pointer/reference is very important in C++.

Nir Friedman
  • 15,634
  • 2
  • 33
  • 63
-1

This statement:

   int *ptr = (int*) &local;

followed by

   *ptr = 100;

is wrong. The standard calls this type of behavior (assigning via a pointer which doesn't match the type of the target of the assignment) "undefined behavior" which means that the compiler is not required to produce a warning message (it would be nice if it did), but it also means the compiler is not required to generate code that implements the statement the way you expect it to.

You can read more about undefined behavior and related language issues here

Dale Wilson
  • 8,374
  • 2
  • 27
  • 47