为什么我们允许改变的&QUOT值; const的"限定的变量?为什么指针允许这一点,但不是分配? [英] Why are we allowed to change values of "const" qualified variables?Why pointers are allowed for this,but not assignment?

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

问题描述

考虑下面的2个节目 PROG1 PROG2 。在这里,如果我试图改变的值常量合格的变量 I 使用指针 PTR ,我得到的警告(不出错)初始化丢弃了指针目标类型的限定|,但程序仍然运行并显示新value.But如果我试图改变 i的值在使用赋值语句的第二个方案,我得到的错误(不报警)的只读变量i的分配|

以下是这premise引起的混乱:

1)我们为什么允许改变只读常量限定变量在任何情况下的价值呢?难道这不打败使用的目的常量预选赛?难道我们不应该得到一个错误,如果我们试图这样做?

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

  // PROG1
#包括LT&;&stdio.h中GT;诠释的main()
{
 const int的I = 8;
 为int * PTR =放;我;
 * PTR = 9;
 的printf(%d个,* PTR); //输出新的价值仍然
}

警告:初始化指针目标类型丢弃预选赛|

  // PROG2
#包括LT&;&stdio.h中GT;诠释的main()
{
const int的I = 8;
我= 10;
的printf(%D,我);
}

错误:的只读变量i的分配|

编辑H2CO3

在这里,我修改常量的值限定的变量超过once.I只得到一个警告,无异于 PROG1

  // PROG3
#包括LT&;&stdio.h中GT;诠释的main()
{
const int的I = 8;
为int * PTR =放;我;
* PTR = 9;
* PTR = 10;
的printf(%d个,* PTR); //打印10
}


解决方案

  

1)我们为什么允许改变在任何情况下只读常量合格变量的值?不打败它使用常量的目的预选赛?


试图通过赋值操作符来改变一个const限定对象是一个约束冲突:

6.5.16下的限制


  

2赋值运算符应有的修改的左值作为其左操作数。


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


  

一个的修改的左值的是不具有数组类型的左值,没有一个不完整的类型,没有一个const限定类型,然后如果是结构或联合,没有任何成员(包括递归,所有的任何成员或元素包含的聚集体或工会)用const限定型。


由于违反约束,它需要每5.1.1.3编译诊断信息(1):


  

如果一个preprocessing翻译单元或翻译单元包含违反任何语法规则或约束的符合标准的实现必须产生至少一种诊断消息(以实现定义的方式确定),即使该行为也明确指定为未定义或实现定义。诊断信息不需要在其他情况下进行生产。


但是,不要求将执行拒绝无效程序,因此诊断消息也可以是警告,而不是一个错误。

不过,修改声明常量通过一个左一个没有const限定的类型不是违反约束,虽然它调用未定义的行为,6.7.3对象(6):


  

如果试图修改通过使用非const限定型左值与一个const限定的类型定义的对象,行为是不确定的。


因为它不是一个约束冲突,也没有无效的语法,它甚至不要求将发出的诊断消息。


  

我们不应该得到一个错误,如果我们试图这样做?


您的必须的,如果你试图通过与const限定型左值修改对象获取诊断信息。

由于这严重违背了申报的意图,大多数编译器发出在这种情况下错误。

如果你试图通过与非const-组队参加型左值修改为const限定类型的对象作为

  const int的I = 8;
为int * PTR =放;我;
* PTR = 9;

在试图修改 I 通过前pression * PTR = 9 调用未定义的行为,但是不是违反约束(或语法错误),因此并不需要一个诊断消息(并且没有给出)。

有用于初始化发出的诊断消息

 为int * PTR =放;我;

,因为这又是一个约束违反,每6.5.16.1(1):


  

以下情况之一应当持有:


  
  

      
  • 左操作具有原子,合格,不合格或算术类型,而右边有算术类型;

  •   
  • 左操作数与右边的类型兼容的结构或联合类型的原子,合格,不合格或版本;

  •   
  • 左操作具有原子,合格或不合格的指针类型,(考虑到类型的左操作数将有左值转换后)两个操作数都指向兼容的类型,的合格或不合格的版本和类型尖头由左派类型的所有预选赛的权指出;

  •   
  • 左操作数具有原子,合格或不合格的指针类型;以及(考虑类型左操作数将具有左值变换后)一个操作数是指向的对象的类型,而另一个是一个指针合格或不合格的版本无效,类型指向左边有类型的所有预选赛指向的权利;

  •   
  • 左操作数是一个原子,合格,不合格的或指针,右边是一个空指针常数;或

  •   
  • 左操作数的类型的原子,合格,不合格或_Bool,而右边是一个指针。

  •   

这是诊断然而通常是一个警告,而不是一个错误,因为人们可以明确地投了常量了,

 为int * PTR =(INT *)及我;

而一个人不能抛弃的常量 I

通过一个指向已经从一个指针虚掷了常量来一个const限定对象类型得到的非const限定的对象类型修改对象是有效的如果指向的对象是可以修改的。愚蠢的例子:

  INT I = 8;
我; const int的* CPTR =放大器//有效的,没有问题的补充常量
为int * mptr =(INT *)CPTR;
* mptr = 9; //没问题,指向者非const


  

2)即使由于一些奇怪的原因,我们被允许改变常量的值为什么改变使用指针(允许进行只读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.

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

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