关于左值 右值的一些研究
中国人的优良传统总是喜欢考一些看起来稀奇古怪但是实际上有没有什么用的一些题目,从而来显示自己出题水平的高超,深以难倒广大考生为乐,就比如这一道坑爹的题目:贴上代码:
int i=3; int a=(i++)+(i++); a=?
看到这种题目我就瞬间抓狂了,说句实话我是真心佩服那帮中国所有的出题人,怎么恶心人怎么出,真心我去年买了个表。
对于这种未定义行为的c语言我是不赞成的,本身的定义都模糊的东西怎么可以拿出来用呢,这不是明显逻辑上的犯抽吗?尽管对这种题目很蛋疼,但是做为一个万年中国应试教育下的孩子,我还是对这种题目打算好好研究下,当然,如果我要是这么研究下去就和我题目的主题不符了,我这里拐了个弯,我先研究了下关于运算符优先级的问题,尽管这个表达式的优先级看起来是那么的一目了然。
我先随机抽取了几个单目运算符的表达式,贴代码:gcc 编译
int a=9; int *p=&++a; int tmp=*&a; int tmp_1=!--++a; int tmp_2=--++a; int tmp_4=--a++; int tmp_3=!++a;
结果报错,有几条错误如下,错误结果如下:lvalue required as unary ‘&’ operand;lvalue required as decrement operand ,翻译过来就是在自加运算和&一元操作中必须要为左值,很好我们现在终于来到了我们的主题,对于左值和右值的区别,我们老师以前模糊的和我们有过简单的交流,左值就是赋值操作符左边的数,是可以进行修改的,右值是赋值操作符右边的数,是不可以修改的,同样的左值也不一样在赋值操作符的左边,也可以在右边,
比如 int i=2;
int j=i;
很明显这么简单的解释根本无法解释上述的错误,左值和右值依旧是拦路虎。
经过网上的资料参考,消化吸收后,真心感谢网上的开源精神,看到这么一句话——赋值操作符、自增/自减操作符 (++/–)、取地址操作符 (&,注意该操作符同时要求操作数不能是bit field,以及不能使用register进行修饰) 等要求其操作数必须是左值。对应我上述代码,颇有隔靴搔痒之嫌。几番研究,恍然大悟。贴code
int i=0; (++i)=5; (i++)=5;
编译错误已出;lvalue required as left operand of assignment 赋值左边的操作数要求是左值,我们首先确定了i是一个左值,进行自增自减当然是可以的不会报错,但是自增表达式的值不是一个左值,那么赋值操作符当然无法通过,要求左边必须是左值,当然这种情况在c++中因为运算符重载的关系已经变过了,我们这里不加以引申,后期如果可以的话我还会加以讨论,我们这里只进行对于C语言的研究。
我姑且认为自增表达式中我们得到的值应该是i的一份临时拷贝,只不过i++ 与++i 一个是返回i的拷贝然后才进行i的对i这个操作数的加1,一个是加1之后返回这个数的拷贝,都是一份临时的拷贝,我们并不知道这个表达式的值放在内存的什么地方,也无法保证表达式的值一次还会放在他的老地方,所以++是一个返回右值的表达式。
明白了这个关系,那么我们用一些式子来加深对左值和右值的概念
char cha='a'; char *p=&cha; *p='a'; char tmp=*p; char tmp_1=*p+1; char tmp_2=*(p+1); *(p+1)='b'; char tmp_3=(*p)+1; char *tmp_4=++p; char *tmp_5=p++; char tmp_6=*++p; *++p='c'; char tmp_7=*p++; *p++='d'; char tmp_8=++*p; //++*p='d'; char tmp_9=(*p)++; //(*p)++='c'; char tmp_10=++*++p; //++*++p='c'; char **p1=&p; char tmp_11=*++*p1; *++*p1='c'; //char tmp_12=*++++p; //*++++p='a';
这些式子摘自http://blog.sina.com.cn/s/blog_8af6bbd10100ybid.html 特此声明。明白了这些式子相信对于左右值理解更加深刻。暂时就说这么多,以后关于c++的继续补充。