有意思的c代码

某博客里看到这么一段代码,用多个编译器编译出来都无法确定结果,因为结果不一样,代码如下:
复制内容到剪贴板
代码:
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才对,欢迎讨论

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值