为什么我们可以改变“const"的值?限定变量?为什么允许指针,但不允许赋值? [英] Why are we allowed to change values of "const" qualified variables?Why pointers are allowed for this,but not assignment?

查看:33
本文介绍了为什么我们可以改变“const"的值?限定变量?为什么允许指针,但不允许赋值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下 2 个程序 prog1prog2.这里如果我尝试更改 const 限定变量 i 的值 使用指针 ptr,我收到警告(不是错误)初始化丢弃来自指针目标类型的限定符|",但程序仍然运行并显示新值.但是如果我尝试使用赋值语句在第二个程序中更改 i 的值,我会得到 error(不是警告)assignment of read- 仅变量 'i'|.

这里是由这个前提引起的混淆:

1)为什么我们可以在任何情况下更改只读的const 限定变量的值?这是否违背了使用const 的目的限定符?如果我们尝试这样做,我们不应该得到错误吗?

2) 即使由于一些奇怪的原因我们被允许更改常量的值,为什么区分使用指针更改只读 const 限定变量的值(这是允许的),带有警告)并通过使用赋值操作(这是不允许的并且会给我们一个错误)?

//prog1#include int主(){const int i=8;int *ptr=&i;*ptr=9;printf("%d",*ptr);//仍然打印新值}

警告:初始化会丢弃来自指针目标类型的限定符|

//prog2#include int main(){const int i=8;我=10;printf("%d",i);}

错误:只读变量i"的赋值|

编辑 H2CO3

这里我多次更改了const限定变量的值.我只收到警告,与prog1

相同

//prog3#include int主(){const int i=8;int *ptr=&i;*ptr=9;*ptr=10;printf("%d",*ptr);//打印 10}

解决方案

1) 为什么我们可以在任何情况下更改只读 const 限定变量的值?这不是违背了使用 const 限定符的目的吗?

尝试通过赋值运算符更改常量限定对象是违反约束的:

6.5.16 在约束下:

<块引用>

2 赋值运算符应有一个可修改的左值作为其左操作数.

可修改的左值在 6.3.2.1 (1) 中定义:

<块引用>

可修改的左值是没有数组类型、没有不完整类型、没有const限定类型的左值,如果是结构或联合,没有任何具有 const 限定类型的成员(递归地包括所有包含的聚合或联合的任何成员或元素).

作为违反约束,它需要来自编译器根据 5.1.1.3 (1) 的诊断消息:

<块引用>

如果预处理翻译单元或翻译单元违反任何语法规则或约束,即使该行为也明确指定为未定义,符合要求的实现应至少产生一个诊断消息(以实现定义的方式标识)或实现定义.在其他情况下不需要产生诊断消息.

但是不需要实现来拒绝无效程序,因此诊断消息也可能是警告而不是错误.

然而,通过一个没有 const 限定类型的左值修改声明为 const 的对象不是约束违反,尽管它会调用未定义的行为,6.7.3 (6):<块引用>

如果尝试通过使用具有非 const 限定类型的左值来修改由 const 限定类型定义的对象,则行为未定义.

由于它不是约束违规或无效语法,因此它甚至不需要发出诊断消息.

<块引用>

如果我们尝试这样做,我们不应该得到错误吗?

如果您尝试通过具有 const 限定类型的左值修改对象,您必须收到诊断消息.

由于严重违反了声明的意图,大多数编译器在这些情况下都会发出错误.

如果您尝试通过具有非 const 限定类型的左值来修改具有 const 限定类型的对象,例如

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

尝试通过表达式 *ptr = 9 修改 i 调用未定义的行为,但不是约束违规(或语法错误),因此不需要诊断消息(没有给出).

为初始化发出了诊断消息

int *ptr = &i;

因为这又违反了约束,根据 6.5.16.1 (1):

<块引用>

符合下列条件之一:

  • 左侧操作数具有原子、限定或非限定算术类型,右侧具有算术类型;
  • 左操作数具有与右操作数兼容的结构或联合类型的原子、限定或非限定版本;
  • 左操作数具有原子的、限定的或非限定的指针类型,并且(考虑左操作数在左值转换后的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,指向的类型to by the left 拥有右边所指类型的所有限定符;
  • 左操作数具有原子、限定或非限定指针类型,并且(考虑左操作数在左值转换后的类型)一个操作数是指向对象类型的指针,另一个是指向限定或void 的非限定版本,左边指向的类型具有右边指向的类型的所有限定符;
  • 左边的操作数是一个原子的、限定的或非限定的指针,右边是一个空指针常量;或
  • 左操作数的类型是原子的、限定的或非限定的 _Bool,右操作数是一个指针.

然而,该诊断通常是警告而不是错误,因为人们可能会显式地将 const 丢弃,

int *ptr = (int*)&i;

而人们不能从 i 中抛弃 const.

通过一个指向非const限定对象类型的指针修改一个对象是有效的if指向的对象是可修改的.愚蠢的例子:

int i = 8;const int *cptr = &i;//有效,添加const没问题int *mptr = (int*)cptr;*mptr = 9;//没问题,指针是非常量

<块引用>

2) 即使由于一些奇怪的原因我们被允许更改常量的值,为什么区分使用指针(这是允许的,有警告)更改只读 const 限定变量的值和通过使用赋值操作(这是不允许的并且会给我们一个错误)?

直接分配给具有 const 限定类型的对象不仅违反约束,而且明显违反规定的语义.声明一个对象 const 明确表示我不希望该对象被修改".

通过指向非 const 限定类型的指针修改对象不是约束违规,并且只有当指针具有 const 限定类型时才会出现未定义的行为.允许将指向 const 限定类型的指针转​​换为指向相应的非 const 限定类型的指针,并且通过该指针修改被指点对象可能是有效的,因此您只会收到警告,并且仅当未进行转换时明确的.

在给定的简短示例中,编译器可以检测到指针对象具有 const 限定类型,因此修改会调用未定义的行为,但通常这很困难,而且通常无法检测到.因此,编译器甚至不会尝试检测简单的情况,这是不值得的.

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:

1)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 a const qualifier?Shouldn't we get an error if we attempt to do so?

2)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
}

解决方案

1) 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 a const qualifier?

Trying to change a const-qualified object through an assignment operator is a constraint violation:

6.5.16 under Constraints:

2 An assignment operator shall have a modifiable lvalue as its left operand.

Modifiable lvalues are defined in 6.3.2.1 (1):

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

As a constraint violation, it requires a diagnostic message from the compiler per 5.1.1.3 (1):

A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) 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. Diagnostic messages need not be produced in other circumstances.

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):

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.

Since it's not a constraint violation nor invalid syntax, it doesn't even require a diagnostic message to be emitted.

Shouldn't we get an error if we attempt to do so?

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

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

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

int *ptr = &i;

because that is again a constraint violation, per 6.5.16.1 (1):

One of the following shall hold:

  • the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
  • the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
  • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
  • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type 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 by the left has all the qualifiers of the type pointed to by the right;
  • the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
  • the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.

That diagnostic is however usually a warning and not an error because one may explicitly cast the const away,

int *ptr = (int*)&i;

whereas one cannot cast away the const from i.

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:

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 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)?

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.

这篇关于为什么我们可以改变“const"的值?限定变量?为什么允许指针,但不允许赋值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆