常量表达式和不可修改的左值之间有什么区别?

时间:2017-08-14 15:13:55

标签: c

来自C in a Nutshell:

  

常量表达式

     

编译器识别源代码中的常量表达式   并用它们的值替换它们。由此产生的常数值   必须可以在表达式的类型中表示。你可以使用常数   表达式允许使用简单常量。

     

运营商   常量表达式与其他表达式的规则相同   表达式。因为常量表达式是在翻译时评估的   但是,时间不能包含函数调用或操作   修改变量,例如赋值。

  1. 什么是常量表达式?它没有定义常量表达式

  2. 常量表达式和不可修改的左值之间有什么区别(例如数组名​​称,已用const声明的左值)

  3. 常量表达式总是非左值吗?

  4. 不可修改的左值是否为常量表达式?

4 个答案:

答案 0 :(得分:6)

  

什么是常量表达式?

§6.6-常量表达式:

  

可以在转换期间而不是运行时期间计算常量表达式,因此可以在常量可以使用的任何位置使用。

常量表达式的一个约束是

  

常量表达式不应包含赋值,递增,递减,函数调用或逗号运算符,除非它们包含在未评估的子表达式中 115)

  

常量表达式和不可修改的左值之间有什么区别?

不可修改的左值不是常量表达式。 不可修改的值是不能用于修改对象的左值

int const i = 5;

i指的是一个const对象,但它是一个左值,一种称为不可修改的左值的特殊左值。

无论标准说什么“左值”,它实际上意味着“可修改的左值”(你不会在标准中找到它但是为了清晰起见)

现在让我再解释一下。

int x = 5;
int const *p;

x是一个非const对象,它是一个可修改的左值。 p是指向const int对象的指针。

p = &x;  // This will raise a warning though and hazardous to do.

以上赋值使用限定转换将类型指针的值转换为int ,将值指向const int 。<登记/> *px是指向同一对象的两个不同表达式。可以使用x

修改此abject
--x;  

但是这不能使用*p来完成,因为它是一个不可修改的左值。

--(*p); // Error

常量表达式和不可修改的左值之间的另一个区别是

int const x = 5;
int *p;
/* Assigning address of a non-modifiable object */
p = &x      // Correct
/* Assigning address of a constant expression */
p = &5      // Wrong  
  

常量表达式总是非左值吗?

是的,常量表达总是非左值,即rvalues。

  

是不可修改的左值常量表达式吗?

答案 1 :(得分:4)

  1. 常量表达式在C11 6.6

    中定义
      

    <强>描述

         

    2。可以在转换期间而不是运行时期间评估常量表达式,并且因此可以在常量可以在任何地方使用。

         

    约束

         

    3常量表达式不应包含赋值,递增,递减,函数调用或comma operators,除非它们包含在未评估的子表达式中.15)

         

    4每个常量表达式应计算为其类型的可表示值范围内的常量。

    在某个地方可能允许使用几种类型的常量表达式。有一些常量表达式可以评估为

    • 算术常量表达式,
      • 这是一个特殊情况是整型常量表达式,例如允许(静态分配)数组的大小或位域宽度。
    • 一个空指针常量,
    • 地址常量,或
    • 完整对象类型的地址常量加上或减去整数常量表达式。
  2. 左值或定位器值(可能)指定对象。您可以获取左值的地址。可修改和不可修改的左值之间的区别在于后者不能用作赋值的左侧。或者,C11 6.3.2.1p1

      

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

    不可修改的左值是一个不可修改的左值。

    常量表达式只是...值。它们不存在于内存中 - 没有数字42的地址 - &42毫无意义。

  3. 因此,常量表达式总是非左值。他们没有指定对象。您不能使用6 * 9

  4. 的地址
  5. 不,但......数组类型的左值隐式衰减为指向数组的指针,而这些地址常量。然而,当它们被转换后,它们就不再是左值。

答案 2 :(得分:2)

我认为有多个复杂的问题,让我尝试以一种简单的方式回答它(​​主要通过从标准中明确地复制粘贴,只需创建一个反复的连接我自己的)。

  

1。什么是常量表达式?

C11,章节§6.5,Expressions

  

表达式是一系列运算符和操作数,用于指定a的计算   值,或指定对象或功能,或产生副作用,或   执行它们的组合。

第6.6章,Constant expressions

  

常量表达式可以在翻译期间而不是运行时进行评估   因此可以在常数可能的任何地方使用。

和,P4

  

每个常量表达式应计算为可表示范围内的常量   其类型的值。

Lvalues,章节§6.3.2,

  

左值是一个表达式(对象类型不是void),可能   指定一个对象

,对于 对象 ,§3.15,

  

<强>对象

     

执行环境中的数据存储区域,其内容可以表示   值

一些常量表达式,例如数组(数组名称),字符串文字或地址常量,是左值。否则,对于整个范围的不可修改的左值,由常量对象(或对象引用)和常量表达式组成。

答案 3 :(得分:0)

常量表达式是在编译期间已知(可以评估)值的表达式

examaples

int a = 5+5+3;  //5 + 5 +3 
char []= "Hello"; // string literal "hello"

不可修改的左值是常数对象&amp;不断的经历

Exmaples

const char c;
c = '3';

'3' = c;

可修改的左值必须是可寻址的(即你可以使用&amp;获得它们的地址)并且可分配,即它们可以在赋值运算符的左侧。唯一的例外是没有地址的寄存器变量。