-2

I have written the piece of code below.

{
    const int i = 24;
    int* ptr{};
    ptr = (int*)&i;
    std::cout << i << std::endl;
    *ptr = 13;
    std::cout << i << std::endl;
    std::cout << *ptr << std::endl;
}

In my debugger, I see that the value of i is changed to 13 but my output when I print i after setting it to 13 is still 24.

24
24
13 

Thanks in advance!

Mr Null Pointer
  • 101
  • 1
  • 2
  • 8
  • 6
    Explaining the behavior of _undefined behavior_ is pretty futile, there could have been any result, observed, it doesn't matter. The UB is introduced here: `(int*)`. After that you left what's guaranteed by any c++ standard. – πάντα ῥεῖ Mar 21 '21 at 15:29
  • 5
    The title of the question should be changed from "Understanding const behavior" to "Understanding undefined behavior". – Eljay Mar 21 '21 at 15:39
  • 1
    @Eljay Yeah, we have a good duplicate for that question: https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior – πάντα ῥεῖ Mar 21 '21 at 15:40

1 Answers1

3

In C and C++ const means that the variable is read-only.

The CV qualifiers:

There are two cv-qualifiers, const and volatile

You should have written it the following way:

#include <iostream>

using namespace std;

int main (void) {
    const int i = 24; // not cv-qualified
    const int* ptr; // pointer to const int
    ptr = &i; // OK: cv-qualified access path to unqualified
    //*ptr = 12;  // ill-formed: attempt to modify through ptr to const
    printf("%p\n%p\n", ptr, &i);
    std::cout << i << std::endl;
    std::cout << *ptr << std::endl;
}

or by dropping const if you want to be able to modify the value:

#include <iostream>

using namespace std;

int main (void) {
    int i = 24;
    int* ptr;
    ptr = &i;
    *ptr = 12; // Now OK
    printf("%p\n%p\n", ptr, &i);
    std::cout << i << std::endl;
    std::cout << *ptr << std::endl;
}

You cannot change the value of a const variable, you might still be able to do so but you expose your program to undefined behavior:

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

Your program would still be able to work on a x86 architecture as long as 'i' is placed the stack or in a register which are not read-only in x86 architecture. The .text section (assembly) is the area where memory is read-only.


To illustrate the undefined behavior and which risks you expose yourself at by writing at a read-only memory area please see the below example:

#include <iostream>

using namespace std;

int main (void) {
    const int i = 24;
    int* ptr;
    ptr = (int *)&i;
    *ptr = 12;  // UB
    std::cout << "value at ptr: " << *ptr << std::endl;
    std::cout << "value at i: " << i << std::endl;
    printf("%p address of ptr\n%p address of i\nIs it witchcraft?\n\n", ptr, &i);

    char s[64] = "Ave Caesar, Morituri te salutant\0";
    std::cout << s << std::endl;
    ptr = (int *)s;
    *ptr = 0x20657661; // OK write " eva" at address of s, reversed because of little endianness.
    std::cout << s << " (modified string)" << std::endl; // now with lowercase 'a'
    printf("%p address of ptr\n%p address of s\n\n", ptr, s);

    const char *str  = "Ave Caesar, Morituri te salutant\0"; // in .text segment
    ptr = (int *)str;
    printf("%p address of ptr\n%p address of s\n\n", ptr, str);
    std::cout << str << " (read-only)" << std::endl;
    *ptr = 0x20657661; // attempt to write on read-only memory -> segmentation fault
    std::cout << str << std::endl;
    printf("%p\n%p\n", ptr, s);
    return 0;
}

Output:

value at ptr: 12
value at i: 24
0x7ffcb13df0cc address of ptr
0x7ffcb13df0cc address of i
Is it witchcraft?

Ave Caesar, Morituri te salutant
ave Caesar, Morituri te salutant (modified string)
0x7ffcb13df0e0 address of ptr
0x7ffcb13df0e0 address of s

0x55b0572f3db0 address of ptr
0x55b0572f3db0 address of s

Ave Caesar, Morituri te salutant (read-only)
Segmentation fault (core dumped)
Antonin GAVREL
  • 9,682
  • 8
  • 54
  • 81
  • 1
    Re:"using ptr as a const ptr" -- this muddles two levels of const-ness. It's not the pointer that should be `const` here; it's what the pointer points at. So, as the answer says, the appropriate type is `const int*`. Making the pointer itself `const`, with `int *const ptr`, wouldn't affect the original code. It make the pointer `const`, but doesn't affect the const-ness of the thing it points at. So you couldn't assign a new value to `ptr`m i.e., you couldn't make it point at a different object. +1. – Pete Becker Mar 21 '21 at 15:47