Consider the following 2 programs prog1 and prog2.Here if I try to change the value of the const
qualified variable i
using a pointer ptr
,I get the warning (not error) "initialization discards qualifiers from pointer target type|"
,but the program runs nevertheless and displays the new value. But if I try to change the value of i
in the second program using an assignment statement, I get the error(not warning) assignment of read-only variable 'i'|
.
Here are confusions arising from this premise:
-
Why are we allowed to change the value of a read-only
const
qualified variable in any circumstance? Doesn't it defeat the purpose of using aconst
qualifier? Shouldn't we get an error if we attempt to do so? -
Even if due to some strange reason we are allowed to change values of constants, why the discrimination between changing the value of a read-only
const
qualified variable using a pointer (which is allowed, with a warning) and through using an assignment operation (which is simply not allowed and gives us an error)?
// prog1
#include <stdio.h>
int main ()
{
const int i=8;
int *ptr=&i;
*ptr=9;
printf("%d",*ptr); //Prints new value nevertheless
}
warning: initialization discards qualifiers from pointer target type|
//prog2
#include <stdio.h>
int main()
{
const int i=8;
i=10;
printf("%d",i);
}
error: assignment of read-only variable 'i'|
EDIT for H2CO3
Here I change the value of the const
qualified variable more than once.I only get a warning,the same as in prog1
//prog3
#include <stdio.h>
int main ()
{
const int i=8;
int *ptr=&i;
*ptr=9;
*ptr=10;
printf("%d",*ptr); // Prints 10
}
Best Answer
Trying to change a const-qualified object through an assignment operator is a constraint violation:
6.5.16 under Constraints:
Modifiable lvalues are defined in 6.3.2.1 (1):
As a constraint violation, it requires a diagnostic message from the compiler per 5.1.1.3 (1):
But an implementation is not required to reject invalid programmes, so the diagnostic message could also be a warning instead of an error.
However, modifying an object that is declared
const
through an lvalue that has not const-qualified type is not a constraint violation, although it invokes undefined behaviour, 6.7.3 (6):Since it's not a constraint violation nor invalid syntax, it doesn't even require a diagnostic message to be emitted.
You must get a diagnostic message if you try to modify an object through an lvalue with const-qualified type.
Since that an egregious violation of the declared intentions, most compilers emit an error in these circumstances.
If you try to modify an object with const-qualified type through an lvalue with non-const-qualifed type as in
the attempt to modify
i
through the expression*ptr = 9
invokes undefined behaviour, but is not a constraint violation (or syntax error), hence does not require a diagnostic message (and none is given).There is a diagnostic message emitted for the initialisation
because that is again a constraint violation, per 6.5.16.1 (1):
That diagnostic is however usually a warning and not an error because one may explicitly cast the
const
away,whereas one cannot cast away the
const
fromi
.Modifying an object through a pointer to a non-const-qualified object type which has been obtained by casting away the
const
from a pointer to a const-qualified object type is valid if the object pointed to is modifiable. Stupid example:Directly assigning to an object with const-qualified type is not only a constraint violation, but also an obvious violation of the stated semantics. Declaring an object
const
explicitly says "I don't want that object to be modified".Modifying an object through a pointer to a non-const-qualified type is not a constraint violation, and only undefined behaviour if the pointee has const-qualified type. Converting a pointer to a const-qualified type to a pointer to the corresponding non-const-qualified type is allowed, and modifying the pointee through that pointer may be valid, therefore you get only a warning, and only if the conversion is not made explicit.
In the given short example, the compiler could detect that the pointee has const-qualified type and therefore the modification invokes undefined behaviour, but in general such would be difficult, and often impossible to detect. Therefore, the compiler doesn't even attempt to detect the simple cases, it's not worth the effort.