c++cconstants

Different output of a const variable in C and C++


#include <stdio.h>

int main(void) {
    const int a = 4;

    int *p = (int*)&a;
    printf("%d\n", a);

    *p = 6;
    printf("%d\n", a);

    return 0;
}

The code gives different output on C and C++ compilers:

//In C:
4
6

//In C++:
4
4

Solution

  • Attempting to modify a const value (read-only value) is Undefined Behaviour. The output can be anything, or the program can crash, or propel your dog into space. You've been warned.

    About const, constants and read-only values

    const is a badly chosen keyword, in that it doesn't mean "constant", but "read-only". "constants" is the name given to read-only values, and nothing else. The opposite of "read-only" (here) is "read-write", the opposite of "constant" is "mutable". Mutable is the default in C and C++ (except some rare corner cases, like lambdas). Consider :

    int i = 4;       // (mutable) Value
    int const j = 4; // Read-only value, a.k.a constant
    
    // Pointer to a (mutable) value. You can write to the value through it.
    int *pi = &i;
    
    // Pointer giving read-only access to a value. The value
    // is still mutable, but you can't modify it through cpi.
    int const *cpi = &i;
    
    // Since the value is mutable, you can do that and write to *p2i
    // without trouble (it's still bad style).
    int *p2i = (int*)cpi;
    
    // Pointer giving read-only access to a value.
    // The value is a constant, but you don't care
    // since you can't modify it through cpj anyway.
    int const *cpj = &j;
    
    // This is legal so far, but modify *pj
    // (i.e the constant j) and you're in trouble.
    int *pj = (int*)cpj;
    

    When can you do this ?

    The only situation where you are allowed to cast const away is to pass a pointer (or reference) to a wrongly declared function (or similar) that you cannot modify :

    // Takes a non-const pointer by error,
    // but never modifies the pointee for sure
    int doSomething(Foo *foo);
    
    // Your function, declared the right way
    // as not modifying the pointee
    int callDoSomething(Foo const *foo) {
        // Work around the declaration error.
        // If doSomething ever actually modifies its parameter,
        // that's undefined behaviour for you.
        int bar = doSomething((Foo*)foo);
    }
    

    What can you do not to get bitten ?