C如何识别右值和左值?

时间:2012-06-19 16:27:25

标签: c lvalue rvalue

在C中,有没有办法识别rvalues和左值?

其中一些很容易识别,在分配中,左边的值是左值,右边的值是右值。

但是其他情况下,识别这样的规则很困难。

例如:*p++i++(其中p是指向整数的指针,i是整数) - 如何识别它是rvalue还是lvalue? 上下文++*p++有效,而++i++则没有,因为i++是左值(正如严肃的家伙所说)。

如何识别表达式中的右值和左值?

3 个答案:

答案 0 :(得分:2)

左值(来自左侧(LHS)值)指向内存(或寄存器)存储的内容,您可以为其分配值。 *p++左值,因为它是一个解除引用的指针(即指ptr指向的内存中的位置,而ptr本身的值是地址那个位置)和++*ptr++实际上意味着:*ptr = *ptr + 1; ptr = ptr + 1; - 它递增ptr指向的值,然后递增指针值本身。 i++不是左值,因为i的值增加1并且不引用内存中的位置。您可以将这些值视为final - 它们无法进一步修改,只能用作分配给 lvalues 的值。这就是为什么它们被称为 rvalues (来自右侧(RHS)值)。

LHS和RHS引用赋值表达式A = B;的两侧。 A是LHS,B是RHS。

答案 1 :(得分:2)

术语左值一直是C(并且被转移到C ++并稍后扩展)。开始时没有 rvalue 。我有的草案(N1570)确实列出了两个出现的术语 rvalue - 一次在脚注#64中,一次在索引中。

简而言之:在C世界中,您有两种类型的对象 - lvalues 以及其他所有对象。

请注意,脚注不是标准的一部分,但它们可以提供一些有用的见解。脚注64:

  

64)名称''左值'最初来自赋值表达式E1 = E2,左边是   操作数E1必须是(可修改的)左值。它可能更好地被视为代表一个   对象''定位器值''。在本国际标准中描述的有时称为“右值”   作为''表达的价值''。

     

左值的一个明显例子是对象的标识符。作为另一个例子,如果E是一元的   表达式是指向对象的指针,* E是一个左值,用于指定E指向的对象。

这是一个良好的开端。现在,请记住,表达式是从对象(和运算符)建立起来的,但我们会稍微实现它们,并且在处理对象时需要担心两个基本的事情:类型和值。让我们看看标准对类型限制的说法(6.3.2.1/p1):

  

lvalue是一个潜在的表达式(对象类型不是void)   指定一个对象; 64)如果一个左值在评估时没有指定一个对象,则该行为是未定义的。

另外,请注意下一行很重要:

  

当一个对象被称为具有特定类型时,类型是   由用于指定对象的左值指定。

因此,左值可以用作类型的替代品(我们也会看到)。接下来,让我们看一下对象 左值(6.3.2.1/2)的上下文:

  

当它是sizeof运算符的操作数时,_Alignof运算符,   一元&运算符,++运算符, - 运算符或者左运算符。操作者   或指派运算符

因此,这些是您需要密切关注的运营商。在所有其他情况下:

  

没有数组类型的左值被转换为   存储在指定对象中的值(并且不再是左值);这叫做左值   转换。

有两种特殊类型:数组和函数指示符。这些衰变转换为类型为''指向类型'的指针的表达式 到数组对象的初始元素,而不是左值 / “指向函数返回类型的指针”。 (请记住,我们暂停了 lvalues 可以作为类型使用的事实 - 这正是他们对sizeof_Alignof所做的事情!)

答案 2 :(得分:0)

来自Deitel和Deitel:

变量名称被称为 lvalues (对于“左值”),因为它们可以在赋值运算符的左侧使用。常量被称为 rvalues (对于“正确的值”),因为它们只能在赋值运算符的右侧使用。请注意, lvalues 也可以用作 rvalues ,但反之亦然。

x = 3;  /*  here, x is an lvalue */
c = x;  /*  and in the next line it is an rvalue */