From this article.
Another use for declaring a variable as
register
andconst
is to inhibit any non-local change of that variable, even trough taking its address and then casting the pointer. Even if you think that you yourself would never do this, once you pass a pointer (even with a const attribute) to some other function, you can never be sure that this might be malicious and change the variable under your feet.
I don't understand how we can modify the value of a const
variable by a pointer. Isn't it undefined behavior?
const int a = 81;
int *p = (int *)&a;
*p = 42; /* not allowed */
The constant variable values cannot be changed after its initialization.
Constants are fields whose values are set at compile time and can never be changed.
Changing Value of a const variable through pointerBy assigning the address of the variable to a non-constant pointer, We are casting a constant variable to a non-constant pointer. The compiler will give warning while typecasting and will discard the const qualifier.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With