-3

I have tried the following codes:

#include <iostream>
using namespace std;
struct MyClass {
    const int x;
};
int main() {
    MyClass c = {3};
    const int *p = &c.x;

    cout << "x = " << c.x << endl;
    cout << "&x = " << &c.x << endl;
    cout << "p = " << p << endl;
    cout << "*p = " << *p << endl;
    cout << "*(&x) = " << *(&c.x) << endl;
    cout << endl;

    *(int*)&c.x = 4;

    cout << "x = " << c.x << endl;
    cout << "&x = " << &c.x << endl;
    cout << "p = " << p << endl;
    cout << "*p = " << *p << endl;
    cout << "*(&x) = " << *(&c.x) << endl;

    cout << (p == &c.x) << endl;
    cout << (*p == *(&c.x)) << endl;

    return 0;
}

Then I get the following answer:

x = 3
&x = 0x61fe98
p = 0x61fe98
*p = 3
*(&x) = 3

x = 4
&x = 0x61fe98
p = 0x61fe98
*p = 4
*(&x) = 4
1
1

It seems that I have successfully change the value of constant integer x. But when I directly declare x in main() instead of in a class, I get the totally different answer.

#include <iostream>
using namespace std;

int main() {
    const int x = 3;
    const int *p = &x;

    cout << "x = " << x << endl;
    cout << "&x = " << &x << endl;
    cout << "p = " << p << endl;
    cout << "*p = " << *p << endl;
    cout << "*(&x) = " << *(&x) << endl;
    cout << endl;

    *(int*)&x = 4;

    cout << "x = " << x << endl;
    cout << "&x = " << &x << endl;
    cout << "p = " << p << endl;
    cout << "*p = " << *p << endl;
    cout << "*(&x) = " << *(&x) << endl;
    cout << endl;

    cout << (p == &x) << endl;
    cout << (*p == *(&x)) << endl;

    return 0;
}

The result is

x = 3
&x = 0x61fe98
p = 0x61fe98
*p = 3
*(&x) = 3

x = 3
&x = 0x61fe98
p = 0x61fe98
*p = 4
*(&x) = 3

1
0

That is really strange that (p == &x) is true but (*p == *(&x)) is false!!! I don't know what's going on in the second codes.

Jerry
  • 3
  • 2

1 Answers1

2

What you're doing is undefined behaviour, so anything can happen. The C++ standard says:

Except that any class member declared mutable (10.1.1) can be modified, any attempt to modify a const object during its lifetime (6.8) results in undefined behavior.

And:

[Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier may produce undefined behavior (10.1.7.1). — end note]

So you can cast away the "const" to get int* but attempting to actually modify the variable through that pointer is undefined.

The reason you can cast away the const is that it might not actually point to a constant:

int i = 0;
const int* p = &i;
*(int*)p = 1;      // OK, because p points to a non-constant
const int j = 0;
const int* q = &j;
*(int*)q = 1;      // NOT OK, because q points to a constant

In your second example the compiler is making assumptions when optimizing, based on the fact it knows that a constant value will not change, so it doesn't bother testing its value. The assumption is correct because a correct program can never change the value of a constant. Your program is not correct, but that means the compiler isn't required to give a sensible result.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521