签到

05月08日
尚未签到

共有回帖数 0

    雷神

    等级:
    在C++吧看到这样的问题, 以前没引起多大注意, 但细看之下, 猫腻不少.....
    首先看看如下C++代码(所有测试在VC6.0下进行):

    #includeiostream

    int main(){

       const int i = 1;
       int b;
       *(int*)&i = 4;

       b = 4 + 1;
       std::cout  "i = "  i  std::endl;
       return 0;  
    }

    依常理看运行结果应该是4,但它确是1!
    有几种直接看似合理的解释:
    1. *(int*)&i = 4;没有被执行,或者编译器做了手脚,阻止了i的修改;
    2. i被移入寄存器,cout入栈参数i被某个寄存器代替,比如push ebx;
    3. 所有使用i的地方,i的值被立即数代替,cout压入的实则为1,push 1;
    为了证明某个解释的正确,我们最好看看反汇编代码:
    3:    int main(){
    00401570   push        ebp
    00401571   mov         ebp,esp
    00401573   sub         esp,48h
    00401576   push        ebx
    00401577   push        esi
    00401578   push        edi
    00401579   lea         edi,[ebp-48h]
    0040157C   mov         ecx,12h
    00401581   mov         eax,0CCCCCCCCh
    00401586   rep stos    dword ptr [edi]
    4:
    5:        const int i = 1;
    00401588   mov         dword ptr [ebp-4],1
    6:        int b;
    7:        *(int*)&i = 4;
    0040158F   mov         dword ptr [ebp-4],4
    8:
    9:        b = 4 + 1;
    00401596   mov         dword ptr [ebp-8],5
    10:       std::cout  "i = "  i  std::endl;
    0040159D   push        offset @ILT+195(std::endl) (004010c8)
    004015A2   push        1
    004015A4   push        offset string "i = " (0046c01c)
    004015A9   push        offset std::cout (004777e0)
    004015AE   call        @ILT+640(std::operator) (00401285)
    004015B3   add         esp,8
    004015B6   mov         ecx,eax
    004015B8   call        @ILT+250(std::basic_ostreamchar,std::char_traitschar ::operator) (004010ff)
    004015BD   mov         ecx,eax
    004015BF   call        @ILT+475(std::basic_ostreamchar,std::char_traitschar ::operator) (004011e0)
    11:       return 0;
    004015C4   xor         eax,eax
    12:   }

    很显然1,2被淘汰了,那么3呢,只说对了一半,并不完全正确,
    7:        *(int*)&i = 4;
    0040158F   mov         dword ptr [ebp-4],4
    在赋值表达式中,i被确确实实的修改了,但在
    9:        b = 4 + 1;
    00401596   mov         dword ptr [ebp-8],5
    中,i被立即数1代替了!
    再来看cout的参数入栈,
    0040159D   push        offset @ILT+195(std::endl) (004010c8)
    004015A2   push        1
    004015A4   push        offset string "i = " (0046c01c)
    004015A9   push        offset std::cout (004777e0)
    里面连个i的影子都没有,那么i呢?
    004015A2   push 1,
    和9: b = 4 + 1;的情况一样,
    i被立即数1代替了.....哈哈哈哈哈哈.........
    总结: 在C++中,对i的赋值语句中,i在内存的值会被改变,
    但在运算表达式和参数入栈中,编译器会用对应的立即数代替它,
    至于返回i会发生什么,有兴趣的可以自己试试,嘿嘿!

    好了,到此问题绝不能结束,因为这是C语言吧- -.........
    同样的代码,改成C语言:
    #include stdio.h

    int main(){

       const int i = 1;
       int b;
       *(int*)&i = 4;

       b = 4 + 1;
       printf("i = %dn", i);
       return 0;  
    }

    输出多少?认为是1的就大错特错了,结果是4!
    哈哈,晕吧,看反汇编码:

    3:    int main(){
    00401010   push        ebp
    00401011   mov         ebp,esp
    00401013   sub         esp,48h
    00401016   push        ebx
    00401017   push        esi
    00401018   push        edi
    00401019   lea         edi,[ebp-48h]
    0040101C   mov         ecx,12h
    00401021   mov         eax,0CCCCCCCCh
    00401026   rep stos    dword ptr [edi]
    4:
    5:        const int i = 1;
    00401028   mov         dword ptr [ebp-4],1
    6:        int b;
    7:        *(int*)&i = 4;
    0040102F   mov         dword ptr [ebp-4],4
    8:
    9:        b = 4 + 1;
    00401036   mov         dword ptr [ebp-8],5
    10:       printf("i = %dn", i);
    0040103D   mov         eax,dword ptr [ebp-4]
    00401040   push        eax
    00401041   push        offset string "i = %dn" (0042001c)
    00401046   call        printf (00401080)
    0040104B   add         esp,8
    11:       return 0;
    0040104E   xor         eax,eax
    12:   }

    对于赋值和运算表达式,编译器的处理一样,但参数入栈:
    0040103D   mov         eax, dword ptr[ebp-4]
    00401040   push        eax
    00401041   push        offset string "i = %dn" (0042001c)
    这回压的是正经的i(dword ptr[ebp-4]),
    因为i在前面被改变了,所以结果为4!

    总结总结: 对于C语言,编译器对赋值和运算表达式的处理同C++,
    但被压入的参数i,为其自身,并不是立即数!
    对于返回值,自己去试...

    最后还要唠叨两句,这些测试都是在6.0中进行的,不保证其他编译器
    的处理结果,更不保证优化后的结果,发贴目的,只是为了各吧友在
    遇到类似问题后,能够参考分析,不至晕头转向,无从下手...

    最后的最后,对于压栈规则,标准C/C++有相关规定么???

    楼主 2016-02-05 18:50 回复

共有回帖数 0
  • 回 帖
  • 表情 图片 视频
  • 发表

登录直线网账号

Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号 意见反馈 | 关于直线 | 版权声明 | 会员须知