3

Why can you kind of cheat compiler this way:

const int a = 5;
*((int*)&a)=5;   // VC/armcc does not complain

when above is "abridged" equivalent of this:

const int *ptr2const = &a;
int *ptr = ptr2const;      // as expected error is raised here
*ptr = 5;
Artur
  • 7,038
  • 2
  • 25
  • 39
  • 2
    The second version of your code is not 'equivalent' to the first. The C language requires explicit casts to remove qualifiers from pointer types; a correct compiler can (and should) reject the second piece of code as you've written it. Sadly most just issue a warning. – R.. GitHub STOP HELPING ICE Nov 16 '10 at 23:16

7 Answers7

10

Casting is your way of telling the compiler "I know what I'm doing", so it doesn't complain. Unfortunately, in this instance, you will invoke undefined behaviour.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
7

C-style casts allow you to cast away constness like in your example. In C++, you would normally use the new style casts such as static_cast<>, which don't allow you to cast away constness. Only const_cast<> allows you to do that.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 1
    ..C compiler does not prevent you from writing to const variables and that const (apart from some obvious situations) does not help you much :-D – Artur Nov 16 '10 at 23:38
  • @Artur: Sure it does. When you attempt to modify a constant variable, you get a compiler error. It doesn't get more straightforward than that. What it does let you do is explicitly cast types, so you can do stupid things all day long. But don't misplace that stupidity and say the C compiler or const isn't helpful; it's on you. – GManNickG Nov 16 '10 at 23:41
  • @GMan - I agree - I do not write such code on daily basis but today I've seen void pointer to const volatile as an argument to a routine and started to play with it and it turned out (was not really expecting that) that theoretically you can do anything with a memory area pointed to by that pointer and adding const will not make compiler to even warn you. That is why I wrote that apart from some obvious situations (like dereferencing and assignment) your compiler will not try to do its best to stop you from writing to const area/variable. I did not expect compiler to just "ignore" it. – Artur Nov 17 '10 at 00:01
  • @Artur: Right. Const is just a compile-time type annotation that is way less useful and flexible than type annotations present in many other languages. It's more or less useless, though plenty of people still use it as a sort of code-documentation thing. – Conrad Meyer Nov 17 '10 at 19:11
4

To be equivalent, the 2nd line of the 2nd snippet

int *ptr = ptr2const;      // as expected error is raised here

should be written as

int *ptr = (int *)ptr2const;
pmg
  • 106,608
  • 13
  • 126
  • 198
2

Because C throws away a lot of type safety in order to gain a lot of speed instead. It cannot prevent you from doing incorrect things. It may try to warn you that you are doing incorrect things, but you can always work around the compiler if that is your goal.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
2

Convert your constant to a string and you may find that while the compiler will let you cast away the const (inadvisable though it may be), the linker may put the constant string in read-only memory leading to a runtime crash.

Ben Jackson
  • 90,079
  • 9
  • 98
  • 150
1

C-style casts, such as (int*) are equivalent to C++ const_cast in their ability to cast away constness, so you can side-step const-correctness by using them, although such use is unrecommended (can lead to undefined behaviour).

int main()
{
    const int x = 1;
    (int&)x = 2;
    std::cout << x << std::endl;
}

On my system, the above writes 1 to stdout. You might experience different behaviour.

On the other hand...

void foo(const int& x)
{
    (int&)x = 2;
}

int main()
{
    int x = 1;
    foo(x);
    std::cout << x << std::endl;
}

This writes 2 for me. The difference is that the const used in foo is const as a type qualifier, while in the main in the first example it was used as a storage class. It's not always easy to see whether a variable was declared with const as a storage class, so it's best not to rely on a const_cast or C-style cast to cast away const.

It's best just to use static_cast in most situations as this will warn you at compile time of any suspect behaviour in the form of a compile error.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
  • 1
    They're not equivalent. This specific instance gives the same result as a `const_cast`. The reason for C++ having different cast syntaxes for casts of different nature is precisely to avoid accidentally invoking an invalid cast like this. – André Caron Nov 16 '10 at 23:13
0

This only "works" because the variable is local, and implementations have no way to enforce const-ness on a local (automatic) variable in general (at least not if the address of the variable is ever taken). But as far as the language specification is concerned, this is in the realm of undefined behavior.

If you try this on a global/static variable, you'll quickly find that most implementations can and do enforce const by putting the variable in read-only memory which can be shared between multiple instances of your program.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711