在C中,有没有办法识别rvalues和左值?
其中一些很容易识别,在分配中,左边的值是左值,右边的值是右值。
但是其他情况下,识别这样的规则很困难。
例如:*p++
和i++
(其中p是指向整数的指针,i是整数) - 如何识别它是rvalue还是lvalue?
上下文++*p++
有效,而++i++
则没有,因为i++
是左值(正如严肃的家伙所说)。
如何识别表达式中的右值和左值?
答案 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 */