C 中对左值的要求

问题描述

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;