Can we change the value of an object defined with const through pointers?

Viewed 26894
#include <stdio.h>
int main()
{
    const int a = 12;
    int *p;
    p = &a;
    *p = 70;
}

Will it work?

11 Answers

This code contains a constraint violation:

const int a = 12;
int *p;
p = &a;

The constraint violated is C11 6.5.16.1/1 "Simple assignment"; if both operands are pointers then the type pointed to by the left must have all the qualifiers of the type pointed to by the right. (And the types, sans qualifiers, must be compatible).

So the constraint is violated because &a has type const int *, which has const as a qualifier; but that qualifier does not appear in the type of p which is int *.

The compiler must emit a diagnostic and might not generate an executable. The behaviour of any executable would be completely undefined, since the program does not comply with the rules of the language.

The problem with changing the value of const variable is that the compiler will not expect that to happen. Consider this code:

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

Why would the compiler read a in the last statement? The compiler knows that a is 12 and since it is const, it will never change. So the optimizer may transform the code above into this:

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

This can lead to strange issues. E.g. the code might work as desired in debug builds without optimization but it will fail in release builds with optimization.

Actually a good optimizer might transform the entire code to this:

printf("%d\n", 12);

As all other code before has no effect in the eye of the compiler. Leaving out code that has no effect will also have no effect on the overall program.

On the other hand, a decent compiler will recognize, that your code is faulty and warn you, since

int * p = &a;

is actually wrong. Correct would be:

const int * p = &a;

as p is not a pointer to int, it is a pointer to const int and when declared like that, the next line will cause a hard compile error.

To get rid of the warning, you have to cast:

int * p = (int *)&a;

And an even better compiler will recognize that this cast breaks the const promise and instruct the optimizer to not treat a as const.

As you can see, the quality, capabilities and settings of the compilerwill decide in the end what behavior you can expect. This implies that the same code may show different behavior on different platforms or when using different compilers on the same platform.

If the C standard had defined a behavior for that case, all compilers would have to implement it and no matter what the standard had defined, it would have been hard to implement, putting a huge burden on everyone who wants to write a compiler. Even if the standard had just said "This is forbidden", all compilers would have to perform complex data flow analysis to enforce this rule. So the standard just doesn't define it. It defines that const values cannot be changed and if you find a way to change them anyway, there is no behavior you can rely on.

Related