




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、一道简单的题目引发的思考+i+i 与 i+i+-Dont believe in magic Understand what your program do ,how they do引言昨晚一时兴起,我脑子就问自己下面的代码会输出什么,也不知道我脑子为什么有这个代码模型,只是模糊的有些印象:01 #i nclude 02 #include 0304 i ntmain(int argc,char* argv)0506int i=3,j;0708j=(i+)+(i+)+(+i); prin tf(i = %d, j = %dn,i,j0910exit(0);您会怎样考虑这个问题呢?您不运行这个程序能
2、准确地说出答案吗?我猜想肯定有大部分人不能肯定且准确地说出答案!如果您不能,这篇文章就是为你准备的,保证您看完之后豁然开朗!请细看下文,outline如下:1、诸君的回答我那这道题目问了几个人,他们的答案不尽相同。1.1、A君的回答 因为i = 3,故依次i+=4 , i+=5 , +i=6 , i最后输出为i = 6;但是由于前面两个 + 是后置+,最后一个+是前置+,故j = 3+4+6 = 13。1.2、B君的回答因为i = 3,故第一个i+后为4,第二个i+后为5,接着做i+i操作=5+5=10,最后与(+i)相加 =10+6=16。1.3、C君的回答因为i = 3,故依次i+=4,i
3、+=5,+i=6,i最后输出为i = 6 ;但是第一 i、第二个i 的+是后置+,先进行i+i操作,然后进行两次i+后置操作,故等价于(i)+(i) = 3+3=6, i+ , i+,最后与+i=6相加等于12。1.4、D君的回答因为i = 3,故依次i+=4 , i+=5 , +i=6 , i最后输出为i = 6;但是前面两个+都是后 置+,故先做i+i+(+i)操作,然后才在i+,i+操作,第三个+是前置+,故等价于i+i +(+i)=3+3+4=10,i+,i+。到底哪个人说得对呢?2、编译器的输出首先让我们先来看看编译器会输出什么?2.1、Visual Studio 的输出运行环境:
4、Win7+VS2005or VS2010,输出如下图所示:rwrw 匚:典inind dows5ysows5ystemtem 3 32cmd.exe2cmd.exei i = = J J =12=12请按任意键継续-2.2、GCC的输出运行环境:Ubuntu 10.04+gcc (Ubuntu4.4.3-4ubuntu5)4.4.3,运行结果如下:netskyubuntuvin test.c netskytibuntu:gcc -o test test cnetskyOubuntu:*$ ./test1 = e. j = 10netskyubuntu:-$2.3、Visual C+ 的输出运行
5、环境: Win7+VC2010 ,输出和 VS 样,及i = 6 & j = 12看到这里你肯定想问 why? why? why?3、分析重编译器的输出结果来看貌似C君、D君的分析都是对的,这种差异跟编译器有直接的关系,因为对于这个表达式怎么编译还没有形成标准,编译器的结合方向不同,答案因此会有所不同。而且当然还包括运算符的优先级等。其实顶多算C君答对了一部分,其他几个人的回答都是错的,详情见下面的分析。3.1、gcc编译器上的分析(i+)+(i+)+(+i) i+i+(+i);i+; i+;即如果表达式中含有i+,一律替换成 i,然后在表达式之后进行i+操作。这样的话上面的代码就可以很好的理
6、解了,即3+3+4=10。3.2、分析gcc编译之后的汇编代码可以对gcc编译之后的执行文件进行反编译分析验证正确性。在Linux下面可以用objdump -d xxx(执行文件)命令反汇编执行文件。反编译之后可以看到如下图所示的代码:68648414&64S414!55push ebp8648415:89 e5mov%esp,ebp864841783 e4 fOand$0 xf fff-fffGresp86454 la83 ec 2&sub864841dC7 44 Z牛 1C 93 Q0 00movl sex3.6xlc(esp)864842460S64S4258b 44 24 lcmov0
7、 xlc(esp),%eax86484291 CO|ddeax,eax804842b03 44 24 1C 01addl $0 xlr0 xlc(%esp)SG4S43063 44 24 lcadd9xlc(esp,eax3343489 44 24 ISmoveaxf0 xlS(esp)8G4843803 44 24 lc 91addl $Sxl,0 xlc(esp)se4S43d83 44 24 lc 01addl S0 xl,Qxlc(esp)864S442b8 30 85 04 93movS0 x804853O,eax80484478b 54 24 18mov0 xl8(esp),edx
8、S04844bQ9 54 24movedxf8x8(esp)804844fSb 54 24 1CmovBxlc(esp)fedx864845389 54 24 04movedx,0 x4(esp)SC4S45789 04 24moveax,(esp)004845ae8 el fe ff ffcall S64S340 8G4845fC7 84 24 0Q 00 0Q 00movl $0 x0,(espl8G48466e8 巳5 fe ff ffcall 8048350 804846b!99nop说明:Linux下采用的是 AT & T的汇编语法格式, Win dows下面采用的是In tel汇编
9、语法格式 二者的主要区别在于:1.指令操作数的赋值方向是不同的In tel :第一个是目的操作数,第二个是源操作数AT &T:第一个是源操作数,第二个是目的操作数2.指令前缀AT &T:寄存器前边要加上,立即数前要加上$In tel :没有这方面的要求至此关键代码已经分析完成,由此可见我们之前对gcc编译器上的分析是正确的。3.内存单元操作数In tel :基地址使用口AT&T :基地址使用()比如:in tel 中 mov ax,bxAT&T 中 movl (%eax),%ebx4.操作码的后缀AT&T中操作码后面有一个后缀字母:丨32位,“ w”6位,“ b”位In tel却使用了在操作数
10、前面加dword ptr, word ptr, byte ptr的格式例如:mov al,bl (Intel)movb %bl %al (AT&T)5.AT & T中跳转指令标号后的后缀表示跳转方向,“表示向前,“ b表示向后F面我们重点分析红框中的代码:movl$0 x3 ,0 x1c(%esp):将 3 赋给 i,即 i=3mov0 x1c(%esp) ,%eax :将 esp 中的 i 放到 eax 中add%eax ,%eax :进行 i+i 操作,即 3+3addl$0 x1 ,0 x1c(%esp):对i进行加1操作,即表达式中的(+i)add0 x1c(%esp),%eax :将
11、 eax 中 i+i 的结果 6,加上 +i 之后的 i,即 6+4=10addl$0 x1 ,0 x1c(%esp):对i进行加1操作,即表达式中的(i+)addl $0 x1 ,0 x1c(%esp):对i进行加1操作,即表达式中的 (i+)3.3、vs编译器上的分析(i+)+(i+)+(+i)(+i)+i+i;i+; i+;即如果表达式中含有前置 +i,首先执行+i操作;表达式中的i+,一律换成i,然后执行加法操作;最后在进行i+操作。这样的话上面的代码就可以很好的理解而来,即首先执行+i,i变为4 了;然后进行i+i+i=4+4+4 ; i+, i+。其实对于VS/VC2010编译器中
12、的可以总结为:当用于四则运算时,前置 +/-的运算优先级最高,后置+/-的运算优先级最小,其它的居中。(跟你书上看到是不是不同!)3.4、分析VS编译之后的汇编代码用W32Dasm 反汇编vs编译生成的exe文件,追踪代码。我们可以看到如下图所示的代码:一 a F A“ L百序i_r | 旳 厂门們Hi 11 cM n 1.)巧 sn 円 W 厂 t cc 窝LisnK-卄“洛114Cn MT * M M:D04112A0pushehp:QO4113A18BE.Cmovebp-resp4 Q 0 X1召丑吕QOOOQQaSFrrv U U U U-004113AS pushr rpushas:
13、004113JB* ipushtidlT004113ACkk fafa B*B* iSETJ*iSETJ*leaedir.dwardptr 已Qp卄_ UU% J.丄 3口 w目号上方! u 0Q Cl 0nbs v色ec”3 E2 0041128*7n CCECELrLu-A-rL-rLrLu-A-rL-rCCDDDC一 0 生 J. X Ji ECF3工:aO41L3BDABstosd-QQ4113BHC745FSQSOOODOiQQSOOODOiQD1CV(bp,:0a4112CEmov奇事“idwodjj工喜ehp 7oa4ii3ce83CO01addeaxPF门门n 口厂门1;004
14、113CB3345F8mcxrdwerdptrttp-1 f AX- U W 4 * 1 i詔吕耆* 鎚BUSYMM”pts abp蔦】rJ A JK BH.峙:UO1% 11工034DF6Adddwardptz stp- *00411.3D4Q 3 4 F aAdd色亡廉“dwardprr【空上(一2 0041 丄.01X7B94DECmevdwordpxretip 1 J r:0041L3LASB55F8mnved3trrdwardp t-r ekp-z 04113 DDU 1a.ddWELK”Q i=00411320395SF3mevdwordpE(efcp - - 1 ,E-djEZ0
15、04113Z38B45F3H1JE3VearrdwordpXi ehpI7004113ZG63G901add.aatiiSiSesFisraKUQVLJ fe SJC:00411SECPRLV4. W JsHf 4xnovt004113129B4SECniev*awrtdwardptr gQp14 :004113F1push电倉MHi 口 Q Ji Jta W启 R a Tj p Swtar Ml1 皿可ecxdHQEdprz eh(?J1UO4 J. 1.3 S 1push-ecic-004i 1.-3FCGa3CopushUJ. F面重点分析一下框中代码:精品文档你我共享mov ebp-0
16、8,3:将3赋给i,即i=3mov eax,dwordptr ebp-08:将ebp中的i的值放到 eax中,是累加器(accumulator),它是很多加法乘法指令的缺省寄存器。dword ptr表示这是一个双字指针,即所要寻址的数据是一个双字(4字节)add eax,1 :对eax中的i进行加1操作mov dword ptr ebp-08 ,eax :将eax中的i赋给ebp中i,即将i力口 1之后的值赋给 也即达到i=i+1的效果mov ecx,dwordptr ebp-08:将 ebp 中的 i 放到 ecx 中add ecx,dwordptr ebp-08:将ebp中的值加上i,即4
17、+4add ecx,dwordptr ebp-08:将 ebp 中的值加上 i,即 4+4+4mov dword ptrebp-14,ecx :将ecx中的值赋给jmov edx,dwordptr ebp-08:将 i 放到 edx 中add edx,1 :对edx中的i进行加1操作mov dword ptr ebp-08 ,edx :将edx中的i赋给ebp中i,即将i力口 1之后的值赋给也即达到i=i+1的效果mov eax,dwordptr ebp-08:将 i 放到 eax 中add eax,1 :对eax中的i进行加1操作mov dword ptr ebp-08 ,eax:将eax中
18、的i赋给ebp中i,即将i力口 1之后的值赋给i,也即达到i=i+1的效果至此,上面表达式的关键运算部分已经分析完成。从这里可以知道,上面我们地VS编译器的分析是正确的。4、发散思维可以说通过上面那么篇幅的介绍,我们对涉及前置+和后置+的加法运算表达式的计算过程有了一个清楚的认识,下面就我们发散一下我们的思维,释放我们的能量。4.1、思维放射您看下面的代码会输出什么,现在知道了吧!view sourcepri nt?01 #i nclude 02 #include 03 04 int main(int argc,char* argv) 05inti=3,j=3,k=3,l=3,m=3 ,n=3
19、,result1,result2,result3,result4,result5,re sult6;07result1=(+i)+(+i);08prin tf(i = 3n);09prin tf(result1= (+i)+(+i) = %dnn,result1);1011result2=(j+)+(j+);12prin tf(j = 3n);13prin tf(result2= (j+)+(j+) = %dnn,result2);1414result3=(+k)+(+k)+(+k);15prin tf(k = 3n);16prin tf(result3= (+k)+(+k)+(+k) = %
20、dnn,result3);1817result4=(+l)+(+l)+(l+);18prin tf(l = 3n);19prin tf(result4= (+l)+(+l)+(l+) = %dnn,result4);2220result5=(m+)+(m+)+(m+);21prin tf(m = 3n);22prin tf(result5=(m+)+(m+)+(m+) = %dnn,result5);262728result6=(n+)+(+n)+( n+);prin tf(n = 3n);293031 prin tf(result6=( n+)+(+n)+( n+) = %dnn,resul
21、t6);exit(0);请不看结果先自己分析一下,然后和结果对比!4.2、VS的输出运行环境:Win7+VS2005 or VS2010,输出如下图所示:SB C;wi ndow5y5tendow5y5te m m 3 3 2crmd2crmd*C+*iC*+i*C+*i = = IQIQj j = = 3 3vesu.lt2vesu.lt2 = = = G Gk k - - 3 3pesu.Lt3=pesu.Lt3= + + + *! = = ISIS1 1 = = 3 3resiiLtlresiiLtl- - t+L*-*Cl+t+L*-*Cl+ - - 1515m m = = 3 3rere suitssuits
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 云南省楚雄州2022-2023学年高二下学期语文期末试卷(含答案)
- 2025农田地承包合同样本
- 2025各类加工合同范本
- 2025标准汽车买卖合同范本
- 2025如何认定农村土地承包合同的效力
- 2025建筑施工设备租赁合同范本
- 2025广州房屋租赁合同范本2
- 2025简约农业合作合同范本
- 《慢性便秘解析与自我管理》课件
- 《探索人生意义》课件
- 辛弃疾词《青玉案·元夕》
- 公路桥梁塔柱施工平台及通道安全技术要求
- 糖尿病临床诊疗指南:基层实践
- 抖音房产直播敏感词汇表
- (高清版)JTGT 3383-01-2020 公路通信及电力管道设计规范
- 国际公法学马工程全套教学课件
- 微专题地质地貌的形成过程(解析)
- YY/T 0655-2024干式化学分析仪
- 中华民族共同体概论课件专家版2第二讲 树立正确的中华民族历史观
- 四年级四年级下册阅读理解100篇及答案经典
- 中职对口升学复习资料:《汽车机械基础》试题库+答案
评论
0/150
提交评论