左值 右值

来源:互联网 发布:阿青和独孤求败知乎 编辑:程序博客网 时间:2024/04/28 09:52

L-Value and R-Value Expressions

Expressions that refer to memory locations are called “l-value” expressions. An l-value represents a storage region’s “locator” value, or a “left” value, implying that it can appear on the left of the equal sign (=). L-values are often identifiers.

Expressions referring to modifiable locations are called “modifiable l-values.” A modifiable l-value cannot have an array type, an incomplete type, or a type with the const attribute. For structures and unions to be modifiable l-values, they must not have any members with the const attribute. The name of the identifier denotes a storage location, while the value of the variable is the value stored at that location.

An identifier is a modifiable l-value if it refers to a memory location and if its type is arithmetic, structure, union, or pointer. For example, if ptr is a pointer to a storage region, then *ptr is a modifiable l-value that designates the storage region to which ptr points.

Any of the following C expressions can be l-value expressions:

An identifier of integral, floating, pointer, structure, or union type


A subscript ([ ]) expression that does not evaluate to an array


A member-selection expression (–> or .)


A unary-indirection (*) expression that does not refer to an array


An l-value expression in parentheses


A const object (a nonmodifiable l-value)
The term “r-value” is sometimes used to describe the value of an expression and to distinguish it from an l-value. All l-values are r-values but not all r-values are l-values.

Microsoft Specific —>

Microsoft C includes an extension to the ANSI C standard that allows casts of l-values to be used as l-values, as long as the size of the object is not lengthened through the cast. (See Type-Cast Conversions for more information.) The following example illustrates this feature:

char *p ;
short i;
long l;

(long *) p = &l ; /* Legal cast */
(long) i = l ; /* Illegal cast */

The default for Microsoft C is that the Microsoft extensions are enabled. Use the /Za compiler option to disable these extensions.

END Microsoft Specific  

1.   概念
变量和文字常量都有存储区,并且有相关的类型,区别在于变量是可寻址的;
对于每个变量,都有2个值与其相关联:
1>数据值,存储在某个内存地址中,也称右值(rvalue),右值是被读取的值(read value),文字常量和变量都可被用于右值。
2>地址值,即存储数据值的那块内存地址,也称左值(lvalue),文字常量不能被用作左值。
2 . 问题
++(a--)
这个表达式是非法的,因为前增量操作要求一个可修改的左值,而 "a--" 不是左值(即右值)

3 . 前增量和后增量的区别

int a = 0;
(++a) = 10;// 可以

(a++) = 10;//不可以

早期的c语言教材,for循环语句通常写成:
for(int i=0;i<10;i++)
而现在多为:
for(int i=0;i<10;++i)
两者有区别吗?
a++ 即是返回 a的值,然后变量 a 加 1,返回需要产生一个临时变量类似于
{
       int temp = a;
       a=a+1;
       return temp; //返回右值
}
++a 则为:
{
    a=a+1;
    return &a;    //返回左值
}
显然,前增量不需要中间变量,效率更高。

左值和右值这两个概念我想大家都耳熟能详了,但它们究竟是什么以及如何理解它运用它,一开始大家都会感觉比较困难。所以我想写这篇总结性的文章来帮助大家理解它们。希望对大家有帮助。

        

首先我们需要理解左值和右值的定义:

左值指的是如果一个表达式可以引用到某一个对象,并且这个对象是一块内存空间且可以被检查和存储,那么这个表达式就可以做为一个左值。      

右值指的是引用了一个存储在某个内存地址里的数据。

 

从上面的两个定义可以看出,左值其实要引用一个对象,而一个对象在我们的程序中又肯定有一个名字或者可以通过一个名字访问到,所以左值又可以归纳为:左值表示程序中必须有一个特定的名字引用到这个值。而右值引用的是地址里的内容,所以相反右值又可以归纳为:右值表示程序中没有一个特定的名字引用到这个值除了用地址。

 

            好这些都是从定义上理解左值右值,那么我们再用这些定义作为我们的理论基础来总结一下哪些是左值,哪些是右值:

左值:

Expression

Lvalue

x = 42

x

*ptr = newvalue

*ptr

a++

a++

b[0] = 100

b[0]

const int m = 10

m

int& f()

The function call to f()

 

右值:

Expression

Rvalue

100

100

a * b

The expression of a * b

int f()

The function call to f() that does not return reference

以上这些内容都可以用定义来解释为什么这些为左值,而那些为右值。但我要特殊解释一下为什么函数的调用只能作为右值除了这个函数返回的是引用。其实这个也非常好解释,因为如果一个函数返回的值是 内建类型,那么这个返回值是没有办法通过一个名字或者表达式引用到的,同理如果一个函数返回的是一个对象,那么这个对象是一个临时的,也不可能用一个名字访问到。所以函数的调用通常只能作为右值,但如果一个函数返回引用,那么它的返回值就有意义了,因为它是另一个名字的别名,有名字了,所以它就变成了左值。

 

注意:左值能转化为右值,但反之不行。

 

好了,讲了这么多我觉得已经足够,但还要多讲一点,这点就是哪些操作符必需左值.

Operator

Requirement

& (unary)

Operand must be an lvalue.

++ --

Operand must be an lvalue. This applies to both prefix and postfix forms.

= += -= *= %= <<= >>= &= ^= |=

Left operand must be an lvalue.