赋值语句中关于左值和右值的疑惑
对于左值和右值还有一些模糊的地方:
书上说左值(L-value)是指地址值,右值(R-value)是指数据值。
但对于***右值指的是引用了一个存储在某个内存地址里的数据***这句话不是特别清楚,比如说:a = 5,
1、数值5是来自于内存中的某个特定存储区域吗,而且无论数值大小均是这么来的吗(记忆中好像不是的呢)?
2、使用数值5的时候是以copy的方式还是其他的方式得到的?
3、或者是在赋值之前临时创建的大小为int的空间来存储5,并非是从内存中的引用?
4、关于这方面有什么相关的书籍推荐么?
先谢谢各位不吝赐教。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不太清楚题主问的是 C 还是 C++,如果是 C++ 的话,是哪一版标准的 C++。我这里只说 C++11 中关于左值和右值的问题。
粗略的来讲,当一个对象被用作右值(rvalue)的时候,使用的是这个对象的值(它的内容);当一个对象被用作左值(lvalue)的时候,使用的是这个对象的身份(它在内存中的位置)。
对于表达式
a = 5;
,假设a
为int
类型。其中等号左边的表达式a
的类型是左值,因为我们需要用到它的身份(它在内存中的位置),才能把值赋给它。等号右边的表达式5
的类型是右值,因为我们需要用到它的值(它的内容)。数值
5
是 一个 literal,它的类型是右值(更准确的说是 prvalue,见下文),应该是保存在静态内存(static memory)中。无论大小,只要是 literal 都如此,例如2333333333333333ULL
。在表达式
a = 5;
中,应该是内置赋值运算符将5从静态内存复制到变量a
中。对于自定义的赋值运算符,就要看:1. 是否定义了拷贝赋值运算符(copy-assignment operator)和移动赋值运算符(move-assignment operator),2. 等号右侧表达式的值类型,从而确定是拷贝还是移动。
不是。
不清楚有没有专门论述这方面的书籍,不过你可以看看本文末尾参考部分的文档和 C++11 标准。
以下为引申内容。
前提
C++ 中的表达式(expression,例如操作符和它的操作数、变量名等)是根据两个方面进行分类的:类型和值类别。每个表达式都必定属于三个主要值类别(见下文)之一。
C++11 中表达式的值类别
在 C++11 之前,表达式的值类别分为左值(lvalue)和右值(rvalue)两种,而自 C++11 起,表达式的值类别分为 lvalue、xvalue、prvalue、glvalue、rvalue 五种。之所以引入了这么多种值类型,是因为 C++11 中新增的移动语义(move semantics)。
他们之间的关系如下图所示:
表达式的值类别分类的标准是两点:
有无身份(has identity) 即是否能通过比较两个表达式的身份判断他们是否是同一个表达式。
能否被移走(can be moved from) 即能把表达式的值移到其它变量中去,使原变量处于一种不确定但有效的状态(例如能正常析构)。
这5个值类别之间的关系如下表所示:
C++11 标准原文
From C++11 standard § 3.10
参考
C++ 中表达式的值的类别:Value categories
C++ 中值分类名称的变化由来:“New” Value Terminology
C++0x 到 C++11 值分类名称的变化:n3055
这种常量都在代码段里(.text section)。
推荐: 深入理解计算机系统
C语言不是很精通,但是还是在此说一下自己的理解,如有不正确请指出。
个人觉得,“右值”不应该仅仅是指内存地址中的数据。比如
a = 5
,5
就是一个直接数而非内存地址,正如汇编中可以直接往寄存器中写直接数,也可以写内存地址中的数一样。因为对这种直接数取地址的话是没有意义的。我只知道
java
中的String
在直接赋值为字符串时,该字符串是共享常量池中的字符串的,但是C语言中不知道有没有类似的机制。对于a = 5
这种赋值来说应该和直接的立即数写入差不多;而对于int a;int b = 5; a = b;
这种赋值来说应该是拷贝无疑。这时b
就是“引用了某个内存地址里的数据”。个人觉得对于这种简单赋值来说临时创建空间存储然后拷贝过去在实现上看应该没有必要(没有求证过)。
平常不用C,而且本人学习不深,无法给出有价值的推荐。
以上都是个人见解,没有求证过,供题主参考。如有错误还请指出。
不晓得你看的什么书,我不大明白这个地址值和数据值的定义
至于5所在的内存位置,对于这种整数来说,对于编译器来讲一般都是使用立即数直接赋值,5并没有临时存在于什么地方,
就像是把5放在a所在的栈上的位置,那么这句话就是 a = 5;
如果是字符串,有可能存储在其他位置比如代码段,然后拷贝过来,这样就是 str = "123143";
其他的我不是很懂
但是:
左值和右值都是针对表达式而言的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象。
一个区分左值与右值的便捷方法是:看能不能对表达式取地址,如果能,则为左值,否则为右值