var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-333696-1']); _gaq.push(['_trackPageview']); _gaq.push(['_trackPageLoadTime']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })();
  • 2008年03月22日

    ++i和i--

    分类:

    工具:Visual C++ 9.0(2008)/Turbo C+IDA Pro

    平台:WinXP SP2

     

    代码

    #include <iostream>

    using namespace std;

     

    int _tmain(int argc, _TCHAR* argv[])

    {

          int i=8;

          printf("%d,%d,%d,%d,%d",++i,--i,i--,i++,-i--);

          cout<<++i<<","<<--i<<","<<i--<<","<<i++<<","<<-i--<<endl;

    }

    注:灰色代码为C++调用,两者输出结果一致。

     

    Debug输出为7,7,8,7,-8,用IDA Pro 5.2反汇编看到

    _wmain proc near

     

    var_D8= dword ptr -0D8h

    var_D4= dword ptr -0D4h

    var_D0= dword ptr -0D0h

    var_8= dword ptr -8

     

    push    ebp

    mov     ebp, esp

    sub     esp, 0D8h

    push    ebx

    push    esi

    push    edi

    lea     edi, [ebp+var_D8]

    mov     ecx, 36h

    mov     eax, 0CCCCCCCCh

    rep stosd

    mov     [ebp+var_8], 8      ;8赋值给i

    mov     eax, [ebp+var_8]    ;i存进eax寄存器

    neg     eax                   ;求补,eax值变为-i-8

    mov     [ebp+var_D0], eax  ; [ebp+var_D0] 即第5个参数值为-8

    mov     ecx, [ebp+var_8]    ;i存进ecx寄存器

    sub     ecx, 1                 ;ecx17

    mov     [ebp+var_8], ecx     ;i=i--7

    mov     edx, [ebp+var_8]     ;i存进edx寄存器

    mov     [ebp+var_D4], edx    ;[ebp+var_D4] 即第4个参数值为7

    mov     eax, [ebp+var_8]     ;再次将i存进eax寄存器

    add     eax, 1                 ;eax18

    mov     [ebp+var_8], eax     ;i=i++8

    mov     ecx, [ebp+var_8]     ;再次将i存进ecx寄存器

    mov     [ebp+var_D8], ecx   ; [ebp+var_D8] 即第3个参数值为8

    mov     edx, [ebp+var_8]    ;再次将i存进edx寄存器

    sub     edx, 1                 ;edx-17

    mov     [ebp+var_8], edx     ;i=i--7

    mov     eax, [ebp+var_8]     ;再次将i存进eax寄存器

    sub     eax, 1                  ;eax16

    mov     [ebp+var_8], eax      ;i=--i6

    mov     ecx, [ebp+var_8]      ;再次将i存进ecx寄存器

    add     ecx, 1                  ;ecx17

    mov     [ebp+var_8], ecx      ;i=++i7

    mov     esi, esp

    mov     edx, [ebp+var_D0]    ;5个参数从右至左开始入栈

    push    edx

    mov     eax, [ebp+var_D4]

    push    eax

    mov     ecx, [ebp+var_D8]

    push    ecx

    mov     edx, [ebp+var_8]

    push    edx

    mov     eax, [ebp+var_8]

    push    eax

    push    offset aDDDDD   ; "%d,%d,%d,%d,%d"

    call    ds:__imp__printf

    add     esp, 18h

    cmp     esi, esp

    call    j___RTC_CheckEsp

    xor     eax, eax

    pop     edi

    pop     esi

    pop     ebx

    add     esp, 0D8h

    cmp     ebp, esp

    call    j___RTC_CheckEsp

    mov     esp, ebp

    pop     ebp

    retn

    _wmain endp

     

    Release输出为 8,8,8,8,-8

    _main proc near          ;编译器在编译过程中直接优化然后输出结果

    push    0FFFFFFF8h      ;-i

    push    8

    push    8

    push    8

    push    8

    push    offset aDDDDD   ; "%d,%d,%d,%d,%d"

    call    ds:__imp__printf

    add     esp, 18h

    xor     eax, eax

    retn

    _main endp

     

    Borland  Turbo C v2.01输出结果为7,6,8,7,-8

    _main proc near

     

    argc= word ptr  4

    argv= dword ptr  6

    envp= dword ptr  0Ah

     

    push    bp

    mov     bp, sp

    push    si

    mov     si, 8           ;8赋值给i

    mov     ax, si          ;i存进ax

    dec     si               ;i=i—7

    neg     ax              ;求补,ax值为-i-8

    push    ax              ;5个参数入栈值为-8

    mov     ax, si           ;再次将i存进ax

    inc     si                ;i=i++8

    push    ax               ;4个参数入栈值为7

    mov     ax, si           ;再次将i存进ax

    dec     si                ;i=i—7

    push    ax               ;3个参数入栈值为8

    dec     si                ;i=--i6

    mov     ax, si           ;再次将i存进ax

    push    ax               ;2个参数入栈值为6

    inc     si                 ;i=++i7

    mov     ax, si            ;再次将i存进ax

    push    ax               ;1个参数入栈值为7

    mov     ax, 194h

    push    ax              ; format

    call    _printf

    add     sp, 0Ch

    pop     si

    pop     bp

    retn

    _main endp

     

    从上面的结果可以看出,虽然参数均是从右至左入栈,但每个编译器对运算符处理策略的不同,导致了结果的不确定。因此它不适合出现在程序中,当然更不适合用作笔试/面试题了。

     

    上面的结果同样也瞥现一般++ii++效率更高的原因。

     

    【资源】

    Intel® 64 and IA-32 Architectures Software Developer's ManualsVolume 2A: Instruction Set Reference, A-MVolume 2B: Instruction Set Reference, N-Z

    ECMA C# and Common Language Infrastructure Standards

    分享到:

    历史上的今天:

    GAE Python运行环境 2011年03月22日

    评论

  • 没能看出来那点显示出++i更有效率。而且对TC的目标代码来说mov在前时执行更快。

    而且,那条printf,语义上就是错误的……像是在做RE
    回复skyfoo说:
    我写的结论是“一般++i比i++效率更高”,可以从TC中比较寄存器操作;此文最初并不是针对这个来说,而是对于题目自身。printf的语义,不明白你说的意思,是语义还是语法?何况还有未注释的C++输出。
    2008-04-02 14:50:41