问题描述
What are rvalues,lvalues,xvalues,glvalues,and prvalues? 中有对左值的相当详尽的描述,但这是针对 C++ 的,我认为其中很多不适用于 C。
我对左值的理解如下:
-
数组不是,但它们的下标值可能是,只要它们不是数组。例如:
int arr[3][2]; arr // no --> int[3][2] arr[1] // no --> int[2] arr[1][1] // yes --> int
-
结构可以直接或通过成员访问,例如
.
或->
,只要它们不计算为数组即可。例如:struct Member {int id}; Member member = {.id=2},*member_ptr = &member; member = {.id=3}; // ok member_ptr = &member; // ok member.id=3; // ok member_ptr->id=4; // ok
-
&
运算符的地址不能。例如:a = 7; b = &a; &b = &a; // invalid
-
值运算符
*
只要不引用数组即可。int x[2][2] = {{1,2},{3,4}}; *(x+1)=3; // not ok,evaluates to x[2] *(*(x+1)+1) = 3; // ok
除了更明显的情况(例如执行 7=x
)之外,是否还有我的理解中缺少的主要项目?或者上面有哪些不正确的项目?
解决方法
C standard 在 6.3.2.1p1 节中定义了一个左值,如下所示:
lvalue 是可能指定对象的表达式(对象类型不是 void
);如果左值在评估时未指定对象,则行为未定义。当一个对象被称为具有特定类型时,该类型由用于指定该对象的左值指定。 可修改左值是没有数组类型、没有不完整类型、没有const限定类型的左值,如果是结构体或联合体,则没有任何成员具有 const 限定类型的(递归地包括所有包含的聚合或联合的任何成员或元素)。
这个定义包括数组,但是数组不是可修改的左值。
间接运算符 *
的结果也是一个左值,因为它引用了一个对象。如果结果对象是数组,这也适用。
数组下标运算符 []
也会产生左值,因为 x[y]
完全等同于 *(x + y)
。
成员访问运算符 .
和成员指针运算符 ->
的结果也是左值。
复合字面量也是左值。例如,以下是有效的:
int *p = (int [3]){1,2,3};
p[0] = 4;