4

在 K&R 第 1 章中:

该语句++nc提供了一个新的运算符 ,++表示加一。您可以改为编写nc = nc + 1,但++nc更简洁且通常更高效。

什么时候预增量比替代方案更有效?至少对于大多数事情来说,两者的汇编都是add(edit: or inc) 指令。它们何时不同?

4

5 回答 5

10

该文本早已过时。在 70 年代,编译器可能会为 ++n 产生更有效的输出,但现在可能是这样。所有现代编译器都会产生相同的代码。

于 2011-12-23T09:02:30.737 回答
3

至少对于大多数事情来说,两者的程序集都是 add 指令。

这并不完全正确:通常有一个单独的“递增”指令。但是,这无关紧要,因为任何半体面的编译器都会为++ncand生成相同的机器代码nc = nc + 1

换句话说,没有性能差异。这本书写的时候可能有编译器不是很好的时候,但现在已经没有了。

于 2011-12-23T09:03:08.417 回答
2

我不确定,我只是在大声思考(也许我不应该):也许在 K&R 的时代,++nc被编译成比nc = nc + 1(例如,增量指令,而不是加法)更有效的东西。然而,如今,编译器可能会自动优化这一点。

于 2011-12-23T09:03:09.853 回答
1

这是我可以看到的gcc -S <filename>。我会让你得到你想要的!

>
> cat 1.c
    #include <stdio.h>

    int main()
    {
        int i=0;
        ++i;

        return 0;
    }

>
> cat 2.c
#include <stdio.h>

int main()
{
    int i=0;
    i++;

    return 0;
}

>
> cat 3.c
#include <stdio.h>

int main(void)
{
    int i=0;
    i = i + 1;

    return 0;
}
>
> gcc -S 1.c 2.c 3.c
>
>
> diff 1.s 2.s
1c1
<       .file   "1.c"
---
>       .file   "2.c"
>
> diff 2.s 3.s
1c1
<       .file   "2.c"
---
>       .file   "3.c"
>
> diff 3.s 1.s
1c1
<       .file   "3.c"
---
>       .file   "1.c"
>
>

以下是.s文件的内容,1.c与 2.s 和 3.s 相比,说明相同!

> cat 1.s
        .file   "1.c"
        .text
.globl main
        .type   main, @function
main:
.LFB2:
        pushq   %rbp
.LCFI0:
        movq    %rsp, %rbp
.LCFI1:
        movl    $0, -4(%rbp)
        addl    $1, -4(%rbp)
        movl    $0, %eax
        leave
        ret
.LFE2:
        .size   main, .-main
        .section        .eh_frame,"a",@progbits
.Lframe1:
        .long   .LECIE1-.LSCIE1
.LSCIE1:
        .long   0x0
        .byte   0x1
        .string "zR"
        .uleb128 0x1
        .sleb128 -8
        .byte   0x10
        .uleb128 0x1
        .byte   0x3
        .byte   0xc
        .uleb128 0x7
        .uleb128 0x8
        .byte   0x90
        .uleb128 0x1
        .align 8
.LECIE1:
.LSFDE1:
        .long   .LEFDE1-.LASFDE1
.LASFDE1:
        .long   .LASFDE1-.Lframe1
        .long   .LFB2
        .long   .LFE2-.LFB2
        .uleb128 0x0
        .byte   0x4
        .long   .LCFI0-.LFB2
        .byte   0xe
        .uleb128 0x10
        .byte   0x86
        .uleb128 0x2
        .byte   0x4
        .long   .LCFI1-.LCFI0
        .byte   0xd
        .uleb128 0x6
        .align 8
.LEFDE1:
        .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-48)"
        .section        .note.GNU-stack,"",@progbits
>
于 2011-12-23T09:16:01.770 回答
1

对于“正常”变量,应该没有其他答案所暗示的区别。只有合格,结果可能会有所不同ncvoloatile对于这样的变量,+1表单必须nc首先计算加载的表达式,nc然后执行加法。对于++表单,编译器仍然可以采取捷径并在适当的位置增加变量。

于 2011-12-23T10:43:57.407 回答