++i与i++一道简单的题目引发的思考Word下载.docx

上传人:b****5 文档编号:18636189 上传时间:2022-12-30 格式:DOCX 页数:10 大小:177.11KB
下载 相关 举报
++i与i++一道简单的题目引发的思考Word下载.docx_第1页
第1页 / 共10页
++i与i++一道简单的题目引发的思考Word下载.docx_第2页
第2页 / 共10页
++i与i++一道简单的题目引发的思考Word下载.docx_第3页
第3页 / 共10页
++i与i++一道简单的题目引发的思考Word下载.docx_第4页
第4页 / 共10页
++i与i++一道简单的题目引发的思考Word下载.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

++i与i++一道简单的题目引发的思考Word下载.docx

《++i与i++一道简单的题目引发的思考Word下载.docx》由会员分享,可在线阅读,更多相关《++i与i++一道简单的题目引发的思考Word下载.docx(10页珍藏版)》请在冰豆网上搜索。

++i与i++一道简单的题目引发的思考Word下载.docx

j=(i++)+(i++)+(++i);

08

printf("

i=%d,j=%d\n"

i,j);

09

exit(0);

10

}

您会怎样考虑这个问题呢?

您不运行这个程序能准确地说出答案吗?

我猜想肯定有大部分人不能肯定且准确地说出答案!

如果您不能,这篇文章就是为你准备的,保证您看完之后豁然开朗!

请细看下文,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、第二个i的++是后置++,先进行i+i操作,然后进行两次i++后置操作,故等价于(i)+(i)=3+3=6,i++,i++,最后与++i=6相加等于12。

1.4、D君的回答

但是前面两个++都是后置++,故先做i+i+(++i)操作,然后才在i++,i++操作,第三个++是前置++,故等价于i+i+(++i)=3+3+4=10,i++,i++。

到底哪个人说得对呢?

2、编译器的输出

首先让我们先来看看编译器会输出什么?

2.1、VisualStudio的输出

运行环境:

Win7+VS2005orVS2010,输出如下图所示:

2.2、GCC的输出

Ubuntu10.04+gcc(Ubuntu4.4.3-4ubuntu5)4.4.3,运行结果如下:

2.3、VisualC++的输出

Win7+VC2010,输出和VS一样,及i=6&

j=12

看到这里你肯定想问why?

why?

?

3、分析

重编译器的输出结果来看貌似C君、D君的分析都是对的,这种差异跟编译器有直接的关系,因为对于这个表达式怎么编译还没有形成标准,编译器的结合方向不同,答案因此会有所不同。

而且当然还包括运算符的优先级等。

其实顶多算C君答对了一部分,其他几个人的回答都是错的,详情见下面的分析。

3.1、gcc编译器上的分析

(i++)+(i++)+(++i)<

=>

i+i+(++i);

i++;

即如果表达式中含有i++,一律替换成i,然后在表达式之后进行i++操作。

这样的话上面的代码就可以很好的理解了,即3+3+4=10。

3.2、分析gcc编译之后的汇编代码

可以对gcc编译之后的执行文件进行反编译分析验证正确性。

在Linux下面可以用objdump–dxxx(执行文件)命令反汇编执行文件。

反编译之后可以看到如下图所示的代码:

说明:

Linux下采用的是AT&T的汇编语法格式,Windows下面采用的是Intel汇编语法格式。

二者的主要区别在于:

1.指令操作数的赋值方向是不同的

Intel:

第一个是目的操作数,第二个是源操作数

AT&T:

第一个是源操作数,第二个是目的操作数

2.指令前缀

寄存器前边要加上%,立即数前要加上$

没有这方面的要求

3.内存单元操作数

基地址使用[]

AT&

T:

基地址使用()

比如:

intel中 

mov 

ax,[bx]

T中movl(%eax),%ebx

4.操作码的后缀

T中操作码后面有一个后缀字母:

“l”32位,“w”16位,“b”8位

Intel却使用了在操作数前面加dwordptr,wordptr,byteptr的格式

例如:

moval,bl(Intel)

movb%bl%al(AT&

T)

5.AT&T中跳转指令标号后的后缀表示跳转方向,“f”表示向前,“b”表示向后

下面我们重点分析红框中的代码:

movl 

$0x3,0x1c(%esp):

将3赋给i,即i=3

mov 

0x1c(%esp),%eax:

将esp中的i放到eax中

add 

%eax,%eax:

进行i+i操作,即3+3

addl 

$0x1,0x1c(%esp):

对i进行加1操作,即表达式中的(++i)

0x1c(%esp),%eax:

将eax中i+i的结果6,加上++i之后的i,即6+4=10

对i进行加1操作,即表达式中的(i++)

对i进行加1操作,即表达式中的(i++)

至此关键代码已经分析完成,由此可见我们之前对gcc编译器上的分析是正确的。

3.3、vs编译器上的分析

(++i)+i+i;

即如果表达式中含有前置++i,首先执行++i操作;

表达式中的i++,一律换成i,然后执行加法操作;

最后在进行i++操作。

这样的话上面的代码就可以很好的理解而来,即首先执行++i,i变为4了;

然后进行i+i+i=4+4+4;

i++,i++。

其实对于VS/VC2010编译器中的可以总结为:

当用于四则运算时,前置++/--的运算优先级最高,后置++/--的运算优先级最小,其它的居中。

(跟你书上看到是不是不同!

3.4、分析VS编译之后的汇编代码

用W32Dasm反汇编vs编译生成的exe文件,追踪代码。

我们可以看到如下图所示的代码:

下面重点分析一下框中代码:

mov[ebp-08],3:

moveax,dwordptr[ebp-08]:

将ebp中的i的值放到eax中,是"

累加器"

(accumulator),它是很多加法乘法指令的缺省寄存器。

dwordptr表示这是一个双字指针,即所要寻址的数据是一个双字(4字节)

addeax,1:

对eax中的i进行加1操作

movdwordptr[ebp-08],eax:

将eax中的i赋给ebp中i,即将i加1之后的值赋给i,也即达到i=i+1的效果

movecx,dwordptr[ebp-08]:

将ebp中的i放到ecx中

addecx,dwordptr[ebp-08]:

将ebp中的值加上i,即4+4

将ebp中的值加上i,即4+4+4

movdwordptr[ebp-14],ecx:

将ecx中的值赋给j

movedx,dwordptr[ebp-08]:

将i放到edx中

addedx,1:

对edx中的i进行加1操作

movdwordptr[ebp-08],edx:

将edx中的i赋给ebp中i,即将i加1之后的值赋给i,也即达到i=i+1的效果

将i放到eax中

将eax中的i赋给ebp中i,即将i加1之后的值赋给i,也即达到i=i+1的效果

至此,上面表达式的关键运算部分已经分析完成。

从这里可以知道,上面我们地VS编译器的分析是正确的。

4、发散思维

可以说通过上面那么篇幅的介绍,我们对涉及前置++和后置++的加法运算表达式的计算过程有了一个清楚的认识,下面就我们发散一下我们的思维,释放我们的能量。

4.1、思维放射

您看下面的代码会输出什么,现在知道了吧!

viewsourceprint?

inti=3,j=3,k=3,l=3,m=3,n=3,result1,result2,result3,result4,result5,result6;

result1=(++i)+(++i);

i=3\n"

);

result1=(++i)+(++i)=%d\n\n"

result1);

11

result2=(j++)+(j++);

12

j=3\n"

13

result2=(j++)+(j++)=%d\n\n"

result2);

14

15

result3=(++k)+(++k)+(++k);

16

k=3\n"

17

result3=(++k)+(++k)+(++k)=%d\n\n"

result3);

18

19

result4=(++l)+(++l)+(l++);

20

l=3\n"

21

result4=(++l)+(++l)+(l++)=%d\n\n"

result4);

22

23

result5=(m++)+(m++)+(m++);

24

m=3\n"

25

result5=(m++)+(m++)+(m++)=%d\n\n"

result5);

26

27

result6=(n++)+(++n)+(n++);

28

n=3\n"

29

result6=(n++)+(++n)+(n++)=%d\n\n"

result6);

30

31

请不看结果先自己分析一下,然后和结果对比!

4.2、VS的输出

4.3、GCC的输出

根据前面我们挖掘到的规则,我们可以得到result3之外所有其它答案。

最后,还有一点要说明的是:

gcc中的加法运算表达死中,是按照从左到右按顺序,如果运算符两边有++i操作数,就先进行++i操作,然后进行加法运算;

vs中的加法运算表达式中,则不一样,只要表达式中有++i操作数,就要先计算,最后才是进行加法运算。

这也是为什么result3不同的原因!

加法运算可以扩展到减法、乘法、除法运算和前置--、后置--。

但是如果是四则混合运算还要考虑加、减、乘、除的优先级问题。

5、感慨

通过这么多分析,我们可以算得上是对涉及++、--的运算表达式计算过程有了透彻理解!

我在挖掘这个计算过程的路上,可是化了不少功夫也在刚开始分析汇编代码时遇到了一些困难,但这颗求知的心,推动着我坚持要去弄清楚它!

最后我想说:

请不要写这种语句!

理由很简单,它既不好理解又不好维护,最重要的是它的结果会因编译器的不同而不同。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 表格类模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1