5664|1

72

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

关于递增(++)/递减(--)运算符 [复制链接]

关于递增(++)/递减(--)运算符 记得几天前看到过一个帖子,是关于++运算符的. 大致是对于: a = *p++; a = *p(++); 这样2个语句的运行结果是一样的,感到不理解. 今天比较闲,想发个帖子讨论下这个. 只要你看过几本关于C或者C++的书,上面都会对++,--这2个运算符介绍下,你多多少少会知道它们的意思和用法. 书上会告诉你: 前置的++是先加,然后取出,后置的++是先取出,然后递加. 之后一般会有一两个例子,告诉你怎么用. 但更高级一点的例子就没有了. 你如果曾经写过向下面的程序: int i; ++++i; //ok i++++; //不能通过编译 一般的书上就找不到答案了.顶多告诉你不能那么做.至于为什么不能那么做,没有答案. 你说你不打算知道这些,你就只要知道"先加后取数","先取数后加"的概念就可以了,你不需要编那些代码. 但你总有需要看别人代码的时候,说不定就有那些语句, 不是? 以下是一些测试题目: 假设下面的变量是如下声明的. int i = 9; int ar[] = {1, 2, 3, 4}; int * p = ar; int f(int x) {return x}; 那么以下语句是否正确?能否通过编译?为什么? 如果能通过编译,那么运行后的结果是什么?为什么? 1> i++++; 2> ++i++; 3> (++i)++; 4> ++i = 5; 5> i++ = 5; 6> i = *p++; 7> i = *(p++); 8> i = (*p)++; 9> i = ++f(); 如果你能正确知道以上全部语句的结果,那么你才是真正理解了递增(++)/递减(--)运算符; --------------- 待续
此帖出自单片机论坛
点赞 关注
 

回复
举报

72

帖子

0

TA的资源

一粒金砂(初级)

沙发
 

回复: 关于递增(++)/递减(--)运算符

------------------------------------------------ 道歉: 写这个东西,本来是一时兴起,闹着玩的.不想批评居多. 本来是不准备再理会这个贴了,但忍不住又看了下. coputer00提示<3><4>没法编译,我找了KEIL ARM RV 编译了下,确实如此. 不过如果是C++文件,是可以编译通过的. 再尝试了VC6.0, VC2003, C++ builder, 这2句都不能在C下编译,只能在C++下编译通过. 我写这个东西的时候,参考的是ISO/IEC C++ 14882 标准,都是在C++下编译的. 所以没发现C下不能编译. 我重新查阅了ISO/IEC C 9899 标准,象++i这样的前缀式,并没有明确说明它的返回值可以作为左值使用. 对此我表示歉意. 我更正我的说法如下: 以下的述说都基于ISO/IEC C++, 于C下,下面的说法有可能是错误的. 再次表示歉意. 附: C标准 Constraints The operand of the prefix increment or decrement operator shall have qualified or unqualified real or pointer type and shall be a modifiable lvalue. Semantics The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is equivalent to (E+=1). See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers. C++标准: The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated). The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a completely-defined object type. The value is the new value of the operand; it is an lvalue. If x is not of type bool, the expression ++x is equivalent to x+=1. [Note: see the discussions of addition (5.7) and assignment operators (5.17) for information on conversions. ] ------------------------------------------------ 如果要知道以上语句的答案,需要先说明几个概念. 1) 左值和右值 左值是可以写在=号左边的表达式,必须是一个非const的变量. 右值是可以写在=号右边的表达式,可以是一个常量,一个字面数字,或者说一个任意的可以求值的表达式. 一个可以作为左值的表达式,同时也是可以作为右值使用的. 不是有人建议(或者说提倡)你这么做嘛 if(exp == 5) .... 写成 if(5 == exp) .... 这就是利用了象5这么样的字面数字,只能作为右值使用, 如果你不小心写成了 if(5 = exp) 那么编译器认为这是一个错误. 虽然我不喜欢这么做,但我不否认这么做有它的好处. 2) 临时变量 这里所说的临时变量,不是那种类似 tmp = i; i = j; j=tmp; 的临时变量, 是指那种由编译器暗中产生的"无名字"的临时变量. 比方: int func(...) {...}; int x = func(); 这里实际上有一个临时变量的产生, 就是func()的返回值,它之后作为一个右值,赋给x; 象这种临时变量, 它是不能作为左值使用的,你不能写成这样: func() = 5; //错误, func()的返回值是一个临时变量,不能作为左值使用. 3) 逗号(,)运算符 还记得','运算符吧, 它是一系列的表达式, 之间用','隔开. 运算规则是,从左到右依次计算每个表达式,之后返回最右边的那个表达式. 比如: int i, j, k, l; i = j=2, k=3, l=4; 最后i的结果等于4. 4) 运算符优先级的问题 *(不是乘,是取值的那个符号), ++, --, 都是同一个优先级,结合规律是 右->左 言规正转,开始说递增/递减运算符. 前置的++, 先递增,后取值. 后置的++, 先取值,后递增. 当你写下 ++x , 实际上它等同于表达式: x=x+1, x <a> x++, 等同于表达式: tmp=x, x=x+1, tmp <b> !! 注意<b>中那个tmp, 是一个由编译器产生的临时变量. <a>和<b>中有个重要的区别, <a>返回的是一个可以作为左值使用的变量, <b>返回的是一个只能作为右值使用的临时变量. !!而且,因为有x=x+1的动作,所以x本身必定是一个可以作为左值的表达式. 现在分析下 x++++ 和 ++++x x++++ => (x)(++)(++) 右边的那个(++), 因为它右边没有任何表达式了,所以它只能是一个后置的++, 它作用于 (x)(++) 身上, 而(x)(++)本身也是一个后置式的++, 它的返回值是一个临时的变量,不能作为左值使用,所以这个语句不能通过编译. ++++x => (++)(++)(x) 很显然, 右边的那个(++)是一个前置的++, 作用于(x), 返回是一个可以作为左值的值, 其返回结果作为左边那个(++)的操作数. 所以这个语句是合法的, 执行完后x加了2次. 最后,对前面的题进行解答: 1> i++++; // 不能编译 2> ++i++; // 不能编译, 因为++运算符是右结合的, 所以先计算i++, 结果作为左边++的操作数. // 但i++的返回结果是不能作为左值使用的. 3> (++i)++; // OK. (++i)的结果作为 后置++的操作数 // 结果 i 加了2次 4> ++i = 5; // OK; ++i的返回结果是可以作为左值的 // 最后i的结果等于5 5> i++ = 5; // 不能编译. i++ 不能作为左值使用 6> i = *p++; // => i= *((p)(++)); (因为++, *是右结合的) // 先计算p++, 返回一个p累加前的指针, 作为 * 的操作数 // 结果就是累加前的那个p指针指向的对象的内容 7> i = *(p++); // 因右结合的关系,同6>的表示是一样的,结果也是6>的结果 8> i = (*p)++; // 先计算*p, 得到p所指向的对象, 之后p指向的对象+1, p本身保持不变 9> i = ++f(); // 不能编译. f()的返回是一个临时变量,不能作为左值使用. ====================================== <剧终>
此帖出自单片机论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表