1

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

其中一些很容易识别,比如在赋值中,左边的值是左值,右边的值是右值。

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

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

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

4

3 回答 3

3

左值这个术语一直在 C 中(并被带到 C++ 并在以后扩展)。一开始就没有右值。我的草稿 (N1570) 确实列出了两次出现的右值一词——一次在脚注 #64 中,一次在索引中。

简而言之:在 C 世界中,您有两种类型的对象——值和其他所有对象。

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

64) 名称“左值”最初来自赋值表达式 E1 = E2,其中要求左操作数 E1 是(可修改的)左值。将其视为表示对象“定位器值”可能更好。有时被称为“右值”的东西在本国际标准中被描述为“表达式的值”。

左值的一个明显示例是对象的标识符。再举一个例子,如果 E 是一个一元表达式,它是一个指向对象的指针,那么 *E 是一个左值,它指定 E 指向的对象。

这提供了一个良好的开端。现在,请记住,表达式是由对象(和运算符,但我们稍后会介绍)构建的,在处理对象时需要担心两个基本的事情:类型和值。让我们看看标准对类型限制的说明(6.3.2.1/p1):

左值是一个表达式(对象类型不是 void),它可能指定一个对象;64) 如果一个左值在计算时没有指定一个对象,则行为未定义。

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

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

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

当它是 sizeof 运算符、_Alignof 运算符、一元 & 运算符、++ 运算符、-- 运算符或 . 运算符或赋值运算符

因此,这些是您需要留意的运营商。在所有其他情况下:

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

有两种特殊类型:数组和函数指示符。这些衰减即被转换为类型为''pointer to type''的表达式,该表达式指向数组对象的初始元素,而不是左值/ “指向函数返回类型的指针”(请记住,我们已经暂停了左值可以作为类型工作的事实——这正是他们所做的,sizeof并且_Alignof!)

于 2012-06-19T17:20:17.330 回答
2

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

LHS 和 RHS 指的是赋值表达式的两边A = B;A是 LHS,B是 RHS。

于 2012-06-19T16:49:36.857 回答
0

来自 Deitel 和 Deitel:

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

x = 3;  /*  here, x is an lvalue */
c = x;  /*  and in the next line it is an rvalue */
于 2012-06-19T16:55:46.820 回答