分享
 
 
 

Inside i++

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

i++、++i、i=i+1、效率怎么样?看过一本书上说,i++比i=i+1好

的地方是因为i=i+1中的那个1要占用一个寄存器,所以速度没有

i++快,于是我想验证一下。另外,以前听说过Java中的“i=i++”

得不到正确结论,也就是应该是“先累加再赋值”,但Java经过这

种运算后,i值居然没有变化。所以在这里,想一并把这几个问题

在C中验证一下。

=====================测试的C源程序====================

#01: #include <stdio.h>

#02:

#03: main()

#04: {

#05: int i=0, j=0;

#06: i=i++;

#07:

#08: i=i+1;

#09: i++;

#10: ++i;

#11:

#12: j=i+1;

#13: j=i++;

#14: j=++i;

#15:

#16: printf("i=%d", i);

#17: }

======================================================

下面是我在 VC++ 6.0 + SP5 / Window 2000环境下对上述源程序的反汇编:

5: int i=0, j=0;

0040D698 mov dword ptr [ebp-4],0

0040D69F mov dword ptr [ebp-8],0

6: i=i++;

0040D6A6 mov eax,dword ptr [ebp-4]

0040D6A9 mov dword ptr [ebp-4],eax

0040D6AC mov ecx,dword ptr [ebp-4]

0040D6AF add ecx,1

0040D6B2 mov dword ptr [ebp-4],ecx

8: i=i+1;

0040D6B5 mov edx,dword ptr [ebp-4]

0040D6B8 add edx,1

0040D6BB mov dword ptr [ebp-4],edx

9: i++;

0040D6BE mov eax,dword ptr [ebp-4]

0040D6C1 add eax,1

0040D6C4 mov dword ptr [ebp-4],eax

10: ++i;

0040D6C7 mov ecx,dword ptr [ebp-4]

0040D6CA add ecx,1

0040D6CD mov dword ptr [ebp-4],ecx

12: j=i+1;

0040D6D0 mov edx,dword ptr [ebp-4]

0040D6D3 add edx,1

0040D6D6 mov dword ptr [ebp-8],edx

13: j=i++;

0040D6D9 mov eax,dword ptr [ebp-4]

0040D6DC mov dword ptr [ebp-8],eax

0040D6DF mov ecx,dword ptr [ebp-4]

0040D6E2 add ecx,1

0040D6E5 mov dword ptr [ebp-4],ecx

14: j=++i;

0040D6E8 mov edx,dword ptr [ebp-4]

0040D6EB add edx,1

0040D6EE mov dword ptr [ebp-4],edx

0040D6F1 mov eax,dword ptr [ebp-4]

0040D6F4 mov dword ptr [ebp-8],eax

=================================================================

下面是我在 SCO UNIX下用cc -g 对上述源程序编译后,用dbx打出的内存汇编代码:

( int i=0, j=0; )

0x0000015e (main:5) mov DWord Ptr [ebp-0x04],$0

0x00000165 (main:5) mov DWord Ptr [ebp-0x08],$0

( i=i++; )

0x0000016c (main:6) mov eax,DWord Ptr [ebp-0x04]

0x0000016f (main:6) inc DWord Ptr [ebp-0x04]

0x00000172 (main:6) mov DWord Ptr [ebp-0x04],eax

( i=i+1; )

0x00000175 (main:8) inc DWord Ptr [ebp-0x04]

( i++; )

0x00000178 (main:9) inc DWord Ptr [ebp-0x04]

( ++i; )

0x0000017b (main:10) inc DWord Ptr [ebp-0x04]

( j=i+1; )

0x0000017e (main:12) mov eax,DWord Ptr [ebp-0x04]

0x00000181 (main:12) inc eax

0x00000182 (main:12) mov DWord Ptr [ebp-0x08],eax

( j=i++; )

0x00000185 (main:13) mov eax,DWord Ptr [ebp-0x04]

0x00000188 (main:13) inc DWord Ptr [ebp-0x04]

0x0000018b (main:13) mov DWord Ptr [ebp-0x08],eax

( j=++i; )

0x0000018e (main:14) inc DWord Ptr [ebp-0x04]

0x00000191 (main:14) mov eax,DWord Ptr [ebp-0x04]

0x00000194 (main:14) mov DWord Ptr [ebp-0x08],eax

======================================================================

1、从上述的汇编代码我们不难看出对于i=i+1; i++; ++i这三个指令的汇编

指令无论是在VC下还是在SCO UNIX的cc下都是一样的(虽然这两个编译器

对其汇编得到的指令不太一样,但是它们对这三条指令的汇编都是一样的,

这里,我是关闭编译器优化的选项,也许现在的编译器自动对之优化了)

在VC下都是:

0040D6B5 mov edx,dword ptr [ebp-4]

0040D6B8 add edx,1

0040D6BB mov dword ptr [ebp-4],edx

在cc下都是:

0x0000017b (main:10) inc DWord Ptr [ebp-0x04]

2、对于复合指令 j=i+1; j=i++; 却有所不同,

在VC下:j=i+1 是三条指令,而 j=i++ 却有五条指令,这也很合理。

在SCO下: j=i+1 和 j=i++ 都是三条指令。(j=i++指令数比VC少)

3、对于i=i++,在VC下可以得到正确的结果 i=1;而在SCO下却是i=0; 这可以

从其汇编看到。

VC对i=i++的汇编是:

0040D6A6 mov eax,dword ptr [ebp-4] //取内存值i到eax

0040D6A9 mov dword ptr [ebp-4],eax //把eax值放到内存i中

0040D6AC mov ecx,dword ptr [ebp-4] //取内存值i到ecx

0040D6AF add ecx,1 //寄存器ecx加1

0040D6B2 mov dword ptr [ebp-4],ecx //把ecx值放到内存i中

SCO对i=i++的汇编是:

//取内存i到寄存器eax中

0x0000016c (main:6) mov eax,DWord Ptr [ebp-0x04]

//对内存i进行累加

0x0000016f (main:6) inc DWord Ptr [ebp-0x04]

//把寄存器eax的值放到内存i中

0x00000172 (main:6) mov DWord Ptr [ebp-0x04],eax

可见,之所以SCO得不到正确的结果的原因了。我已为其加上了注释,相信各位是看得懂的。

【结论】:

1、如果是单语句,无论是i=i+1; i++; ++i;其效率是完全一样的。

2、之所以SCO下的i=i++得不到正确结果,是因为其编译器追求效率的结果。(Java亦如此)

3、观察SCO下的汇编指令“inc DWord Ptr [ebp-0x04]”,难道可以直接操作内存吗?(拿不准)

4、各个产商的编译器各有不同,所产生的语句的指令代码也有所不同,C++就更尤其如此啦。

======================================================================

最后附上Java对i=i++的测试

源程序:

#1: class Test

#2: {

#3: public static void main(String[] argv)

#4: {

#5: int i=0;

#6: i=i++;

#7: System.out.println("i="+i);

#8: }

#9: }

用javac -g Test.java 把其编译成 Test.class。

再用javap -c Test打出其虚拟机指令代码如下:

D:\>javap -c Test

Compiled from Test.java

class Test extends java.lang.Object {

Test();

public static void main(java.lang.String[]);

}

Method Test()

0 aload_0

1 invokespecial #1 <Method java.lang.Object()>

4 return

Method void main(java.lang.String[])

0 iconst_0

1 istore_1

2 iload_1

3 iinc 1 1

6 istore_1

7 getstatic #2 <Field java.io.PrintStream out>

10 new #3 <Class java.lang.StringBuffer>

13 dup

14 invokespecial #4 <Method java.lang.StringBuffer()>

17 ldc #5 <String "i=">

19 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>

22 iload_1

23 invokevirtual #7 <Method java.lang.StringBuffer append(int)>

26 invokevirtual #8 <Method java.lang.String toString()>

29 invokevirtual #9 <Method void println(java.lang.String)>

32 return

可见其中的:

1 istore_1

2 iload_1

3 iinc 1 1

6 istore_1

就是i=i++的虚拟机指令,想来一定和SCO的编译器有异曲同工之处。

【备注】

这段程序的结果是i=0,我是在 j2se 1.4.0 下进行的测试。

虽然说,这是一个BUG,但是有多少人又会写i=i++这种无聊的语句呢?

不过却可以了解一下编译器(解释器)的工作方式。

——

(版权所有,如需转载,请注明作者和出处)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有