10

When I run this code on MS VS C++ 2010:

#include <iostream>

int main() {
    const int a = 10;
    const int *b = &a;
    int *c = (int *)b;
    *c = 10000;
    std::cout << c << " " << &a << std::endl;
    std::cout << *c << " " << a << " " << *(&a) << std::endl;
    return 0;
}

The output is:

0037F784 0037F784
10000 10 10

The motivation for writing that code was this sentence from "The C++ Programming Language" by Stroustrup: "It is possible to explicitly remove the restrictions on a pointer to const by explicit type conversion".

I know that trying to modify a constant is conceptually wrong, but I find this result quite weird. Can anyone explain the reason behind it?

Kinan Al Sarmini
  • 533
  • 3
  • 19

2 Answers2

7

Let's start with the obvious: some of this is platform and compiler dependent.

For starters, see this article on Explicit Type Conversion, and particularly:

A pointer to an object of a const type can be cast into a pointer to a non-const type. The resulting pointer will refer to the original object. An object of a const type or a reference to an object of a const type can be cast into a reference to a non-const type. The resulting reference will refer to the original object. The result of attempting to modify that object through such a pointer or reference will either cause an addressing exception or be the same as if the original pointer or reference had referred a non-const object. It is implementation dependent whether the addressing exception occurs.

So this, explains why it may let you modify the variable without bitching.

Note that you could achieve the same using the cast operators directly, as that's what the compiler will do for you as explained in this article on cast operators, with their order of precedence given.

However, the real trick here is in the memory model. A statically allocated variable like a const int a may actually never have any "physical" location in memory, and is just replaced in place at compile time. (I'm trying to put my finger on the actual reference for this, but so far the closest and best I could grab was this (very nice) SO answer to is memory allocated for a static variable that is never used? - If anyone finds the actual reference, please let us know.)

So here the compiler is simply humoring you, and trying to make some sense of your pointer arithmetic as much as it can, but in the end substitutes a actual values for the 2 last parts of your 2nd cout call.

Community
  • 1
  • 1
haylem
  • 22,460
  • 3
  • 67
  • 96
  • Makes sense, actually modifying const int a = 10 to const int a = x where x is a value that I enter, makes the output: 10000 10000 10000. Thanks! – Kinan Al Sarmini Nov 09 '12 at 00:26
  • @KinanAlSarmini: you're welcome. Very glad I could help, as it took me some time starring at the screen to figure it out. Haven't done much C and C++ in a while, to my dismay. So always happy to dabble into these dark waters every once in a while. – haylem Nov 09 '12 at 00:49
  • 1
    +1 for the compiler is just humoring you - "silly human, why would you want to *do* that?" – Tacroy Nov 09 '12 at 00:50
  • @KinanAlSarmini: in the future though, that sort of question is probably better suited for [StackOverflow](http://www.stackoverfow.com/) than for [P.SE](http://programmers.stackexchange.com/). You'd have gotten a lot more answers and quicker for such a question over there, I think, which is why I had myseld voted for your question to be closed and transferred. – haylem Nov 09 '12 at 00:50
0

The reason is that this is undefined behaviour.

The Stroustrup quote likely refers to the case where the object was not declared const but you have only a const pointer to it.

i.e. This is well-defined (using c-style cast as they appear in question):

int a{10};
const int* pa = &a;

int* b = (int*)pa;
*b = 5;

And this is undefined:

const int a{10};
const int* pa = &a;

int* b = (int*)pa;
*b = 5;

Attempting to modify an object declared const, however you get a non-const pointer to it, is UB.

mythagel
  • 1,789
  • 19
  • 15