Question

As we know the value of constant variable is immutable. But we can use the pointer of constant variable to modify it.

#include <iostream>

int main()
{
    const int integer = 2;
    void* tmp = (void*)&integer;
    int* pointer = (int*)tmp;

    (*pointer)++;

    std::cout << *pointer << std::endl;
    std::cout << integer << std::endl;

    return 0;
}

the output of that code is:

3
2

So, I am confusing what i modified on earth? what does integer stand for?

Was it helpful?

Solution

Modifying consts is undefined. The compiler is free to store const values in read only portions of memory and throw error when you try to change them (free to, not obliged to). Undefined behavior is poor, undesirable and to be avoided. In summary, don't do that.

PS integer and pointer are variable names in your code, tho not especially good names.

OTHER TIPS

You have used unsafe, C-style casts to throw away the constness. C++ is not an inherently safe language, so you can do crazy stuff like that. It does not mean you should. In fact, you should not use C-style casts in C++ at all--instead use reinterpret_cast, const_cast, static_cast, and dynamic_cast. If you do that, you will find that the way to modify const values is to use const_cast, which is exactly how the language is designed.

This is an undefined behavior. The output you get is compiler dependent. One possible explanation for this behavior is as follows.

When you declares integer as a constant, and use it in an expression, a compiler optimization and substitute it with the constant literal you have assigned to it. But, the actual content of the memory location pointed by &integer is changed. Compiler merely ignore this fact because you have defined it as a constant.

See Const Correctness in C++. Give some attention to the assembler output just above the 'The Const_cast Operator' section of this page.

You're wading into Undefined Behavior territory.

If you write

void* tmp = &integer;

the compiler would give you an error. If you wrote good C++ code and wrote

void* tmp = static_cast<void*>(&integer);

the compiler would still give you an error. But you went ahead and used a C-style unprotected cast which left the compiler no option but to do what you told it.

There are several ways the compiler could deal with this, not least of which:

  1. It might take the address of a location in the code segment where the value was, e.g., being loaded into a register.
  2. It might take the address of a location of a similar value.
  3. It might create a temporary by pushing the value onto the stack, taking the address of the location, and then popping the stack.

You would have to look at the assembly produced to see which variant your compiler prefers, but at the end of the day: don't do it it is undefined and that means next time you upgrade your compiler or build on a different system or change optimizer settings, the behavior may well change.

Consider

    const char h = 'h';
    const char* hello = "hello";
    const unsigned char num = 2 * 50 + 2 * 2; // 104 == 'h'
    arg -= num; // sub 104, eax

    char* ptr = (char*)(&h);

The compiler could choose to store an 'h' specially for the purpose of 'ptr', or it could choose to make 'ptr' point to the 'h' in hello. Or it could choose to take the location of the value 104 in the instruction 'sub 104, eax'.

The const key word is just a hint for compiler. Compiler checks whether a variable is const or not and if you modify a const variable directly, compiler yield a wrong to you. But there is no mechanism on variable storage to protect const variables. So operating system can not know which variable is const or not.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top