某博客里看到这么一段代码,用多个编译器编译出来都无法确定结果,因为结果不一样,代码如下:
复制内容到剪贴板
代码:
void main()
{
int i = 1;
printf("%d,%d,%d",i++,++i,i);
printf("/n/n");
}
很普通的代码,i++和++i是一样的,都是自动加1,我分别用了VC、TC和Linux下的GCC编译,结果如下。
VC debug方式编译,结果为2,2,1;Release方式编译,结果为2,3,3
GCC编译结果为2,3,3
TC编译结果为2,2,1
可以看到结果不一样的,于是,我把VC分别用release和debug方式编译的和TC编译的反汇编了,Linux下GCC的就懒得管了,代码贴上来,不过这里说明一点,C入栈是从右到左的顺序。
VC下用Debug方式编译的反汇编:
.text:00401028 mov [ebp+var_4], 1
.text:0040102F mov eax, [ebp+var_4] ;eax=1
.text:00401032 push eax
.text:00401033 mov ecx, [ebp+var_4] ;ecx=1
.text:00401036 add ecx, 1 ;ecx加1,ecx=2
.text:00401039 mov [ebp+var_4], ecx ;[ebp+var_4]现在为2
.text:0040103C mov edx, [ebp+var_4] ;edx=2
.text:0040103F push edx
.text:00401040 mov eax, [ebp+var_4]
.text:00401043 mov [ebp+var_8], eax
.text:00401046 mov ecx, [ebp+var_8]
.text:00401049 push ecx
.text:0040104A push offset aDDD ; "%d,%d,%d"
.text:0040104F mov edx, [ebp+var_4]
.text:00401052 add edx, 1
.text:00401055 mov [ebp+var_4], edx
.text:00401058 call printf
.text:0040105D add esp, 10h
.text:00401060 push offset asc_42201C ; "/n/n"
.text:00401065 call printf
.text:0040106A add esp, 4
.text:0040106D pop edi
.text:0040106E pop esi
.text:0040106F pop ebx
.text:00401070 add esp, 48h
.text:00401073 cmp ebp, esp
.text:00401075 call __chkesp
.text:0040107A mov esp, ebp
.text:0040107C pop ebp
.text:0040107D retn
.text:0040107D main endp
VC下用Release方式编译后的反汇编:
.text:00401000 push 3
.text:00401002 push 3
.text:00401004 push 2
.text:00401006 push offset aDDD ; "%d,%d,%d"
.text:0040100B call sub_401020
.text:00401010 push offset asc_407030 ; "/n/n"
.text:00401015 call sub_401020
.text:0040101A add esp, 14h
.text:0040101D retn
.text:0040101D _main endp
TC编译后的反汇编:
seg000:01FA push bp
seg000:01FB mov bp, sp ;sp和bp平等
seg000:01FD push si
seg000:01FE mov si, 1 ;si=1
seg000:0201 push si
seg000:0202 inc si ;自动加1
seg000:0203 mov ax, si ;ax=2
seg000:0205 push ax
seg000:0206 mov ax, si
seg000:0208 inc si ;自动加1
seg000:0209 push ax ;ax=2
seg000:020A mov ax, 194h
seg000:020D push ax ; format
seg000:020E call _printf
seg000:0211 add sp, 8
seg000:0214 mov ax, 19Dh
seg000:0217 push ax ; format
seg000:0218 call _printf
seg000:021B pop cx
seg000:021C pop si
seg000:021D pop bp
seg000:021E retn
seg000:021E _main endp
Release 方式编译,代码会经过优化的,在编译生成时,计算出了三个i的值,从上面Release方式编译后的反汇编代码中可以看出,三个i的值是直接将计算好的压入栈。编译出了逻辑问题了?编译时i成了一个累加器了,它首先给i赋值,i=1,此时i的值为1,当遇到第一个i++时,i=2了,++i时,i又自动加 1,i=3,最后一个i就是相加后的i,i=3,所以它编译的输出结果是2,3,3。
i值应该是不变化的,也就是int i=1,i就等于1,当遇到第一个i++时,i=2,当遇到第二个++i时,i=2,最后一个i,i应该是i=1,i的值不会随着数位相加而值变化,最后结果应该是2,2,1才对,欢迎讨论