(*&) 是左值还是 r 值?

Is (*&a) a lvalue or a rvalue?

首先,我认为这是一个 rvalue,但以下事实改变了我的想法。

我尝试了一个表达式 &(*&a) 并且它工作正常,但是运算符 & 只能与 lvalue 一起使用,所以 (*&a)lvalue,为什么?

此表达式 &(&a) 无效,将不起作用。

根据 C 标准

1 The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

3 The unary & operator yields the address of its operand. If the operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.

所以表达式 &a 的结果不是左值。因此,您可能不会将运算符 & 应用于 &&a.

等表达式

这是一个演示程序。

#include <stdio.h>

int main(void) 
{
    int x = 10;
    &( &x );

    return 0;
}

编译器gcc 8.3报错

prog.c: In function ‘main’:
prog.c:7:2: error: lvalue required as unary ‘&’ operand
  &( &x );
  ^

这个表达式*&a是有效的,结果是一个左值。

4 The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

请记住,括号不会影响括起来的表达式是否为左值。

Per C 2018 6.5.3.2 4(讨论 unary * 运算符),一元 * 的结果是左值:

… If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object.…

这告诉我们 *&a 是一个左值。但是题中问到的表达式是(*&a),所以要考虑括号的作用

6.3.2.1 2(讨论自动转换)似乎告诉我们 (*&a) 被转换为 *&a 中的值而不是左值:

Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.

然而,6.5.1 5(讨论括号表达式)与此矛盾:

A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression. It is an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or a void expression.

这是C标准的缺陷; 6.5.1 5 和 6.3.2.1 2 相互矛盾。留给我们理解的是,专门针对括号表达式的 6.5.1 5 优先于更一般的 6.3.2.1 2,这就是所有 C 实现的行为方式。

因此(*&a)是一个左值。