++nc vs nc = nc + 1

发布于 2024-12-22 17:48:51 字数 277 浏览 0 评论 0原文

在 K&R 第 1 章中:

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

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

In K&R Ch 1:

The statement ++nc presents a new operator, ++, which means increment by one. You could instead write nc = nc + 1, but ++nc is more concise and often more efficient.

When would pre-increment be more efficient than the alternative? For most things, at least, the assembly for both is the add (edit: or inc) instruction. When do they differ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

野鹿林 2024-12-29 17:48:51

该文本早已过时。在 70 年代,编译器可能会为 ++n 生成更有效的输出,但现在情况并非如此。所有现代编译器都会生成相同的代码。

That text is long out dated. It might have been true in the 70's that compilers would produce more efficient output for ++n, but not any more. All modern compilers will produce identical code.

许久 2024-12-29 17:48:51

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

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

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

For most things, at least, the assembly for both is the add instruction.

That's not quite true: there is often a separate "increment by one" instruction. However, that's irrelevant since any half-decent compiler will produce identical machine code for ++nc and nc = nc + 1.

In other words, there is no performance difference. There may have been when the book was written and compilers were not very good, but there isn't anymore.

只有影子陪我不离不弃 2024-12-29 17:48:51

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

I don't know for sure, I'm just thinking out aloud (maybe I shouldn't): Perhaps in K&R's time, ++nc was compiled into something more efficient than nc = nc + 1 (e.g., an increment instruction, rather than an addition). Nowadays, however, compilers probably optimise this automagically.

少女七分熟 2024-12-29 17:48:51

这是我用 gcc -S 看到的。我会让你得到你想要的!

>
> 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"
>
>

下面是1.c.s文件的内容,与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
>

This is what I could see with gcc -S <filename>. I'll let you derive what you want!

>
> 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"
>
>

The below is the content of the .s file for 1.c and the instructions are identical when compared with 2.s and 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
>
甜中书 2024-12-29 17:48:51

对于“正常”变量,应该没有其他答案所暗示的差异。仅当 ncvoloatile 限定时,结果可能会有所不同。对于这样的变量,+1 形式必须首先计算表达式 nc,即加载 nc,然后执行添加。对于 ++ 形式,编译器仍然可以采用快捷方式并就地增加变量。

For "normal" variables there should be no difference as other answers suggest. Only if nc is voloatile qualified the result could be different. For such a variable the +1 form must first evaluate the expression nc that is load nc and then perform the addition. For the ++ form the compiler still could take shortcuts and increment the variable in place.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文