Praxeolitic
Praxeolitic

Reputation: 24039

When is casting away const legal or illegal? (gcc, clang, and MSVC)

When is casting away const illegal?

In many cases const is simply an annotation for the benefit of the user which is enforced by the compiler. This question is asking for when casting away const is strictly illegal and what part of the C99 standard forbids it (if any)?

I suspect that it must be illegal in some cases because I've observed that const function pointers in the global scope are sometimes inlined by gcc. If these function pointers could be legally modified later in the program then this optimization would be invalid. Additionally I'm pretty sure I've read an explanation for when casting away const is illegal on StackOverflow but I just can't find it. (I think the answer was that const can only be cast away when a variable was originally not declared as const.)

I've tagged this C99 because I'm hoping this is something specified in the C99 standard but if an answer can explain behavior common to the gcc, clang, and MSVC implementations of C99 then that would also be sufficient for me.

(Obviously this is very basic question so I did try and fail to find a duplicate specifically for the C standard. If anyone else can point me to an exact duplicate I'll be happy to close vote. In either case, I think this question title at least helps SSO for this sort of question.)

Upvotes: 3

Views: 837

Answers (1)

AnT stands with Russia
AnT stands with Russia

Reputation: 320401

Casting away constness in never illegal. You can do it freely and legally as much as you want. But attempting to modify the pointed object after casing away the constness might lead to undefined behavior (or it might not, depending on the circumstances).

C99 clearly states

6.7.3 Type qualifiers

5 If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.

(it is 6.7.3/6 in C11).

Note that const in C (and C++) is used in two independent and very different roles: const-qualification of an object itself and const-qualification of an access path to an object.

const int a = 42;  // `a` is a const-qualifiet object

int b = 5;         // `b` is not const-qualified
const int *p = &b; // `*p` is a const-qualified access path to `b`

In the latter case the constness can be legally cast away and the resultant non-const access path can be used to modify the object, provided the object itself is not const

*(int *) p = 6; // nothing formally wrong with it

This is the very reason we have the ability to cast away constness in the language.

But the former (constness of the object itself) cannot be overridden

*(int *) &a = 43; // undefined behavior

The reason is pretty trivial - a const object can be physically located in read-only memory. And even if it isn't, the compiler is still free to compile the code under assumption that the object's value never changes.

This means that in a declaration like

const int *const cp = &b;

these two const have quite different meanings. The first (leftmost) one is a "soft" const, which can be overridden if the conditions are right. But the second const is a "hard" const that cannot be overridden.

So, when you say that "const is simply an annotation for the benefit of the user which is enforced by the compiler", it is only true for const-qualifications of access paths. When it comes to const-qualifications of objects themselves, it is generally a lot more that just just a purely conceptual compiler-enforced "annotation".

Upvotes: 13

Related Questions