Can we modify the value of a const variable?
The author's point is that declaring a variable with register
storage class prevents you from taking its address, so it can not be passed to a function that might change its value by casting away const
.
void bad_func(const int *p) {
int *q = (int *) p; // casting away const
*q = 42; // potential undefined behaviour
}
void my_func() {
int i = 4;
const int j = 5;
register const int k = 6;
bad_func(&i); // ugly but allowed
bad_func(&j); // oops - undefined behaviour invoked
bad_func(&k); // constraint violation; diagnostic required
}
By changing potential UB into a constraint violation, a diagnostic becomes required and the error is (required to be) diagnosed at compile time:
c11
5.1.1.3 Diagnostics
1 - A conforming implementation shall produce at least one diagnostic message [...] if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined.
6.5.3.2 Address and indirection operators
Constraints1 - The operand of the unary
&
operator shall be [...] an lvalue that designates an object that [...] is not declared with theregister
storage-class specifier.
Note that array-to-pointer decay on a register
array object is undefined behaviour that is not required to be diagnosed (6.3.2.1:3).
Note also that taking the address of a register
lvalue is allowed in C++, where register
is just an optimiser hint (and a deprecated one at that).
Can we modify the value of a
const
variable?
Yes, You can modify a const
variable through various means: Pointer hackery, casts etc...
Do Read next Q!!
Is it valid code to modify the value of a
const
variable?
No! What that gives you is Undefined Behavior.
Technically, your code example has an Undefined Behavior.
The program is not adhering to c standard once you modify the const
and hence may give any result.
Note that an Undefined Behavior does not mean that the compiler needs to report the violation as an diagnostic. In this case your code uses pointer hackery to modify a const
and the compiler is not needed to provide a diagnostic for it.
The C99 standard 3.4.3 says:
Undefined behavior: behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements.
NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
Your code compiles, but it has undefined behavior.
The author's point is to use const
and register
so that the code no longer compiles:
const int a = 81;
int *p = (int *)&a; /* no compile error */
*p = 42; /* UB */
register const int b = 81;
int *q = (int *)&b; /* does not compile */