“左值”和“右值”的命名背后的原因是啥?

Posted

技术标签:

【中文标题】“左值”和“右值”的命名背后的原因是啥?【英文标题】:What is the reasoning behind the naming of "lvalue" and "rvalue"?“左值”和“右值”的命名背后的原因是什么? 【发布时间】:2013-03-23 20:27:42 【问题描述】:

C/C++中“左值”和“右值”的命名背后的原因是什么?

【问题讨论】:

既然你知道它们是什么,那你为什么要问呢? 荒谬的是,这被否决了这么多。这是一个非常清楚和有效的问题,并不总是在有关该主题的网络文章中解释,答案有助于记住哪个值类型是哪个。非常值得。 @Syndog 不,这是有问题的,因为 C 和 C++ 从来没有使用完全相同的术语,现在 C++ 有更多的类别。 @curiousguy - 更有理由问。唯一会问为什么有问题的时候是没有好的答案。 @Syndog 表示会有两个答案:C和C++。有些人只知道一种语言的答案。有些人在这里问这么多个 Q 被认为是不好的风格。有些人甚至会因为你同时拥有 C 和 C++ 标签而对你投反对票! 【参考方案1】:

标准提到了这一点:

左值(历史上称为左值,因为左值可能出现在赋值表达式的左侧)[...]

右值(历史上称为右值,因为右值可能出现在赋值表达式的右侧)[...]

也就是说,左值是您可以分配的东西,而右值是您可以分配的东西。

然而,这已经离真相越来越远了。 const 变量是您无法分配的左值的一个简单示例。

const int x = 5;
x = 6; // Error

当涉及运算符重载时,您甚至可以在赋值的左侧显示右值。

我发现将左值视为引用存储在内存中的对象并将右值视为一个值(可能已从内存中读取)更有用。这些概念很好地反映了这个想法。一些例子:

左值到右值可以被认为是从内存中的对象读取值。 大多数运算符需要左值到右值的转换,因为它们使用对象的值来计算结果。 运算符 (&) 的地址需要一个左值,因为您只能获取内存中某物的地址。它不需要获取对象的值来计算其地址。 执行std::move 将左值表达式转换为右值表达式可以被认为是在诱使编译器认为存储在内存中的对象实际上只是一个临时值。

但是,这也不是在所有情况下都成立。这只是一个合理的类比。

【讨论】:

位域的地址也不能取。 "运算符 (&) 的地址需要一个左值,因为" ...因为是这样。这是规则,句号。【参考方案2】:

在过去,“左值”意味着可以放在作业左侧的东西,而“右值”意味着可以放在右侧 作业的一面。

【讨论】:

【参考方案3】:

如果您考虑一下它们可以出现在赋值运算符的哪一侧,这非常直观:

left-value = right-value;

简单地说,lvalue 表示您可以分配给它,rvalue 表示它只能出现在运算符的右侧。

【讨论】:

... 除了含义随时间而变化,您可以在左侧有一个 rvalue 或在右侧需要一个 lvalue用户定义的赋值运算符...但是,从历史上看,这就是原因。【参考方案4】:

在 C 中,lvaluervalue 反映了赋值运算符中的用法。 rvalue 只能出现在= 的右侧,而lvalue 可以出现在任一侧。在 C++ 中类似,但更复杂。

有不可赋值的lvalues,常量变量。

【讨论】:

数组是不可赋值左值的另一个例子。【参考方案5】:

这是简化(稍微复杂的)概念的结果。

lvalues 是 left 值,即。 e.那些“可以在作业的左侧”。这又是一种简化,并非所有左值都可以按原样直接分配(例如,数组不能,只有非const 数组的元素,所以需要下标)。

rvaluesright 值,它们只能位于赋值表达式的右侧。

【讨论】:

【参考方案6】:

左值中的“l”源自“左”值(如赋值运算符的左侧);但是,它现在代表位置值,并且指的是占据内存中某个可识别位置(即具有地址)的任何对象。右值现在是任何不是左值的东西。

【讨论】:

以上是关于“左值”和“右值”的命名背后的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章

& 返回左值或右值是啥?

stdio 函数(sprintf、vsprintf 和 fprintf)背后的命名约定是啥?

绑定 T&& 类型的左值表达式

协议缓冲区和 Avro 中的 ZigZag 编码背后的原因是啥?

与常规缓冲区和制服相比,OpenGL 纹理单元背后的原因是啥?

创建广告时出现代码 200 和子代码 1487194 的 Facebook 错误背后的原因是啥?