1

我搜索了 x++ vs ++x 并在这里找到了一个很好的答案,所以我决定查看 gcc 的汇编输出,看看 x++ 和 ++x 是如何实现的:

主要() { int s = 0; ++s; 返回0;}

编译示例:

gcc mul.c -masm=intel -o mul.asm

++s 的输出:

    .file   "mul.c"
    .intel_syntax
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
    lea %ecx, [%esp+4]
    and %esp, -16
    push    DWORD PTR [%ecx-4]
    push    %ebp
    mov %ebp, %esp
    push    %ecx
    sub %esp, 16
    mov DWORD PTR [%ebp-8], 0
    add DWORD PTR [%ebp-8], 1
    mov %eax, 0
    add %esp, 16
    pop %ecx
    pop %ebp
    lea %esp, [%ecx-4]
    ret
    .size   main, .-main
    .ident  "GCC: (GNU) 4.2.1 20070719  [FreeBSD]"      

x++的输出:

    .file   "mul.c"
    .intel_syntax
    .text
    .p2align 4,,15
.globl main
    .type   main, @function
main:
    lea %ecx, [%esp+4]
    and %esp, -16
    push    DWORD PTR [%ecx-4]
    push    %ebp
    mov %ebp, %esp
    push    %ecx
    sub %esp, 16
    mov DWORD PTR [%ebp-8], 0
    add DWORD PTR [%ebp-8], 1
    mov %eax, 0
    add %esp, 16
    pop %ecx
    pop %ebp
    lea %esp, [%ecx-4]
    ret
    .size   main, .-main
    .ident  "GCC: (GNU) 4.2.1 20070719  [FreeBSD]"

所以,我问 x++ 和 ++x 是否有不同的含义,为什么 GCC 为它们输出一些程序集,不应该有不同的输出?

4

3 回答 3

6

这是一个写得不好的测试用例的例子。表达式的实际结果value++++value永远不会存储,因此编译器可以处理基本类型的等价物。

请改用此示例:

main() { int s = 0, x; x = ++s; return 0; }

main() { int s = 0, x; x = s++; return 0; }

后增量:

(gdb) disas /m main
函数 main() 的汇编代码转储:
1个int main(){
   0x0040138c : 推送 %ebp
   0x0040138d : 移动 %esp,%ebp
   0x0040138f : 和 $0xfffffff0,%esp
   0x00401392 : 低于 $0x10,%esp
   0x00401395 : 调用 0x4018d4

2 个整数 s = 0;
   0x0040139a : 移动 $0x0,0xc(%esp)

3个整数x;
4 x = s++;
   0x004013a2 : 移动 0xc(%esp),%eax
   0x004013a6 : 移动 %eax,0x8(%esp)
   0x004013aa : 包括 0xc(%esp)

5返回0;
   0x004013ae : 移动 $0x0,%eax

6 } 0x004013b3 : 离开
   0x004013b4 : 回复

汇编程序转储结束。
(gdb)

预增量:

(gdb) disas /m main
函数 main() 的汇编代码转储:
1个int main(){
   0x0040138c : 推送 %ebp
   0x0040138d : 移动 %esp,%ebp
   0x0040138f : 和 $0xfffffff0,%esp
   0x00401392 : 低于 $0x10,%esp
   0x00401395 : 调用 0x4018d4

2 个整数 s = 0;
   0x0040139a : 移动 $0x0,0xc(%esp)

3个整数x;
4 x = ++s;
   0x004013a2 : 包括 0xc(%esp)
   0x004013a6 : 移动 0xc(%esp),%eax
   0x004013aa : 移动 %eax,0x8(%esp)

5返回0;
   0x004013ae : 移动 $0x0,%eax

6 } 0x004013b3 : 离开
   0x004013b4 : 回复

汇编程序转储结束。
(gdb)
于 2012-10-06T16:11:23.533 回答
2

要查看不同的输出,您需要做的不仅仅是增加。

主要() { int s = 0; int a = ++s; 返回0;}

如果不使用该值,++s 和 s++ 会做完全相同的事情。

于 2012-10-06T16:10:56.473 回答
2

它被称为“优化”。

在您的情况下,无论是预增量还是后增量(它会导致完全相同的逻辑流程),因此汇编输出是相同的。

这是一个反例:

/*
 * SAMPLE OUTPUT: i++=1, ++j=3
 */
#include <stdio.h>

int
main (int argc, char *argv[])
{
  int i = 1, j= 2;
  printf ("i++=%d, ++j=%d\n", i++, ++j);
  return 0;
}

这是 Visual C++ 汇编器的输出。你会注意到这个例子增加了*“i”和“j”:

; File tmp.c
; Line 5
    push    ebp
    mov ebp, esp
    sub esp, 12                 ; 0000000cH
; Line 6
    mov DWORD PTR _i$[ebp], 1
    mov DWORD PTR _j$[ebp], 2
; Line 7
    mov eax, DWORD PTR _j$[ebp]
    add eax, 1
    mov DWORD PTR _j$[ebp], eax
    mov ecx, DWORD PTR _j$[ebp]
    push    ecx
    mov edx, DWORD PTR _i$[ebp]
    mov DWORD PTR -12+[ebp], edx
    mov eax, DWORD PTR -12+[ebp]
    push    eax
    push    OFFSET FLAT:$SG342
    mov ecx, DWORD PTR _i$[ebp]
    add ecx, 1
    mov DWORD PTR _i$[ebp], ecx
    call    _printf
    add esp, 12                 ; 0000000cH
; Line 8
    xor eax, eax
; Line 9
    mov esp, ebp
    pop ebp
    ret 0
_main   ENDP

这是 gcc 汇编器,带有 -O3。你会注意到它没有做任何增量:编译器只存储最终值 i=1 和 j=3:

.LC0:
        .string "i++=%d, ++j=%d\n"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        subl    $20, %esp
        movl    $3, 8(%esp)
        movl    $1, 4(%esp)
        movl    $.LC0, (%esp)
        call    printf
        addl    $20, %esp
        xorl    %eax, %eax
        popl    %ecx

最后,这是优化的Visual C++ 版本(带有“/Ox”)。您会注意到它是这三个示例中最短的一个:

; File tmp.c
; Line 7
    push    3
    push    1
    push    OFFSET FLAT:$SG399
    call    _printf
    add esp, 12                 ; 0000000cH
; Line 8
    xor eax, eax
; Line 9
    ret 0
_main   ENDP
于 2012-10-06T16:11:38.887 回答