Why are we allowed to change the "const" values ​​of qualified variables? Why are pointers allowed, but not purpose?

Consider the following 2 programs prog1 and prog2 . If I try to change the const value of the qualified variable i using the ptr , I get a warning (and not an error) "initialization discards qualifiers from pointer target type|" , but the program still starts and displays the new value. But if I try to change the value of i in the second program using the assignment operator, I get an error (not a warning) assignment of read-only variable 'i'| .

Here are the confusions arising from this premise:

1) Why are we allowed to change the value of the read-only const variable under any circumstances? Doesn't that defeat the purpose of using the const qualifier? Should we not get an error if we try to do this?

2) Even if for some strange reason we are allowed to change constant values, why is the difference between changing the value of the const variable read-only using the pointer (which is allowed with a warning) and using the 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 the target pointer type |

 //prog2 #include <stdio.h> int main() { const int i=8; i=10; printf("%d",i); } 

error: assigning read-only variable 'i' |

EDIT for H2CO3

Here I change the const value of a qualified variable more than once. I get only 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 } 
+4
source share
2 answers

1) Why are we allowed to change the value of the read-only const variable under any circumstances? Doesn't that defeat the purpose of using the const qualifier?

Attempting to modify an object with content via an assignment operator violates the restriction:

6.5.16 in Restrictions :

2 The assignment operator must have a mutable lvalue as its left operand.

The modifiable values ​​of l are defined in 6.3.2.1 (1):

The modifiable value of lvalue is an lvalue that does not have an array type, does not have an incomplete type, does not have a const type , and if it is a structure or union, it has any member (including, recursively, any member or element of all contained aggregates or unions) with a categorical type.

As a violation of the restriction, a diagnostic message is required from the compiler in 5.1.1.3 (1):

The corresponding implementation should produce at least one diagnostic message (identified in a specific way) if the translation unit or translation unit contains a violation of any syntax rule or restriction, even if the behavior is also explicitly specified as undefined or determined by the implementation. Diagnostic messages should not occur under other circumstances.

But implementation is not required to reject invalid programs, so a diagnostic message can also be a warning instead of an error.

However, changing an object declared const through an lvalue that is not of type const is not a violation of the constraint, although it causes undefined behavior, 6.7.3 (6):

If an attempt is made to modify an object defined using a type specific to const using the value l with a non-constant type, the behavior is undefined.

Since this is not a violation of the constraint and invalid syntax, it does not even require a diagnostic message to be displayed.

Should we not get an error if we try to do this?

You should receive a diagnostic message if you try to modify an object using an lvalue of type const.

Since this is a blatant violation of stated intentions, most compilers emit an error in these circumstances.

If you try to change an object using a const-type using an lvalue with a non-constant qualification type, as in

 const int i=8; int *ptr=&i; *ptr=9; 

an attempt to change i to the expression *ptr = 9 causes undefined behavior, but is not a violation of the restriction (or a syntax error), therefore, it does not require a diagnostic message (and none are specified).

A diagnostic message is issued to initialize

 int *ptr = &i; 

as this again violates the restriction in accordance with 6.5.16.1 (1):

One of the following:

  • the left operand is of atomic, qualified, or unskilled arithmetic type, and the right is of arithmetic type;
  • the left operand has an atomic, qualified or unqualified version of the structure or type of association compatible with the type of law;
  • the left operand has an atomic, qualified, or unqualified pointer type and (given the type that the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type indicated on the left are all type identifiers pointed to by the right ;
  • the left operand has an atomic, qualified, or unqualified pointer type and (given the type that the left operand would have after lvalue conversion), one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to left, has all the qualifiers of the type that the right points to;
  • the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
  • the left operand is atomic, qualified, or unqualified _Bool, and the right is a pointer.

This diagnosis is usually a warning, not an error, since you can explicitly disable const ,

 int *ptr = (int*)&i; 

whereas it is impossible to discard const from i .

Modification of an object using a pointer to an object type not associated with a statement that was obtained by discarding const with a pointer to an object type with a const attribute is valid if the specified object is mutable. Silly example:

 int i = 8; const int *cptr = &i; // valid, no problem adding const int *mptr = (int*)cptr; *mptr = 9; // no problem, pointee is non-const 

2) Even if for some strange reason we are allowed to change constant values, why is there discrimination between changing the value of a constant variable, read-only, using a pointer (which is allowed with a warning) and using an assignment operation (which is simply not allowed and gives us a mistake)?

Direct assignment to an object with a const-qualified type is not only a violation of the restriction, but also an obvious violation of the specified semantics. The declaration of a const object explicitly says "I do not want this object to be modified."

Modifying an object with a pointer to a non-constant type is not a violation of the restriction, but only undefined behavior if the receiver has a const-qualified type. It is allowed to convert a pointer to a type defined using a constant, a pointer to the corresponding non-constant type, and changing the pointer through this pointer can be valid, so you only get a warning and only if the conversion is not explicit.

In the short example given, the compiler could detect that pointee is of type having const, and therefore the modification causes undefined behavior, but in general it would be difficult and often impossible to detect. Therefore, the compiler does not even try to detect simple cases; it is not worth the effort.

+8
source

Why are we allowed to change the value of the read-only const variable under any circumstances?

We do not know. I do not understand why you accept this, and not a single example shows this.

why there is discrimination between changing the value of a read-only constant using a pointer (which is allowed with a warning)

Again: not allowed , therefore, a warning. (Warnings are taken seriously - it seems to you that they have no meaning for them ...) It's just that the compiler does not know that the pointer points to some const -qualified object (because it is declared as non-constant T * ).

As for changing the operation of a variable:

Explanation # 1: undefined behavior (violation of the constraint), so it can do something.

Explanation # 2: it might just be stored on the stack as local automatic variables, and you can really change it.

+2
source

Source: https://habr.com/ru/post/1480704/


All Articles