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

Posted

技术标签:

【中文标题】(*&) 是左值还是 r 值?【英文标题】:Is (*&a) a lvalue or a rvalue? 【发布时间】:2019-08-28 11:42:40 【问题描述】:

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

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

【问题讨论】:

& 永远不会产生左值。 * 总是这样。 【参考方案1】:

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

…如果操作数指向一个函数,则结果是一个函数指示符;如果它指向一个对象,则结果是一个指定该对象的左值。...

这告诉我们*&a 是一个左值。但是问题中问的表达式是(*&a),所以我们必须考虑括号的影响。

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

除非它是 sizeof 运算符、一元 & 运算符、++ 运算符、-- 运算符或 . 运算符或赋值运算符的左操作数,否则为左值没有数组类型的转换为存储在指定对象中的值(不再是左值);这称为左值转换

但是,6.5.1 5(讨论带括号的表达式)与此相矛盾:

带括号的表达式是主表达式。它的类型和值与无括号表达式的相同。如果不带括号的表达式分别是左值、函数指示符或 void 表达式,则它是左值、函数指示符或 void 表达式。

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

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

【讨论】:

【参考方案2】:

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

根据 C 标准

1 一元 & 运算符的操作数应为函数 指示符,[] 或一元 * 运算符的结果,或左值 指定一个不是位域且未声明的对象 使用寄存器存储类说明符。

3 一元 & 运算符产生其操作数的地址。如果 操作数的类型为“type”,结果的类型为“pointer to type”。如果 操作数是一元 * 运算符的结果,也不是该运算符 也没有评估 & 运算符,结果就像两者都是 省略,除了对运算符的约束仍然适用 结果不是左值。

所以表达式&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 );
  ^

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

4 一元 * 运算符表示间接。如果操作数指向一个 函数,结果是一个函数指示符; 如果它指向一个 对象,结果是一个指定对象的左值。如果 操作数的类型为“类型指针”,结果的类型为“类型”。如果 已为指针分配了无效值,则 一元 * 运算符未定义。

请记住,括号不会影响封闭表达式是否为左值。

【讨论】:

但是在 gcc 和 clang 中,表达式都可以正常工作,为什么? @Claim Yang 不,它不起作用。编译器发出错误。 对不起,我的问题似乎出了点问题。我的表达是“&(*&a)”,你帖子中的标准4回答了我的问题。谢谢。 问题中询问的表达式是(*&amp;a),而不是*&amp;a @EricPostpischil 括号不影响表达式是否为左值。

以上是关于(*&) 是左值还是 r 值?的主要内容,如果未能解决你的问题,请参考以下文章

是* p是左值还是左值

指针是左值还是右值?

error C2662 无法将左值绑定到右值 —— 变量永远是左值,即使它的类型为右值引用

左值右值右值引用与move()forward()

左值与右值引用 详解

什么是左值和右值