4

K&R Ch 1:

このステートメント++ncは、新しい演算子を示し++ます。これは、1ずつインクリメントすることを意味します。代わりに書くこともできますがnc = nc + 1++ncより簡潔で、多くの場合、より効率的です。

プレインクリメントが代替よりも効率的であるのはいつですか?ほとんどの場合、少なくとも、両方のアセンブリはadd(edit:またはinc)命令です。それらはいつ違いますか?

4

5 に答える 5

10

そのテキストは古くなっています。70年代には、コンパイラが++ nに対してより効率的な出力を生成することは事実でしたが、それ以上は生成されませんでした。最新のコンパイラはすべて同じコードを生成します。

于 2011-12-23T09:02:30.737 に答える
3

ほとんどの場合、少なくとも、両方のアセンブリはadd命令です。

それは完全には真実ではありません。多くの場合、個別の「1つずつインクリメント」命令があります。ただし、半ばまともなコンパイラはとに対して同一のマシンコードを生成するため、これは関係ありませ++ncnc = 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

「通常の」変数の場合、他の回答が示唆するように違いはないはずです。資格がある場合にのみ、結果が異なる可能性がありncます。voloatileこのような変数の場合、+1フォーム最初ncにロードされている式を評価してncから、加算を実行する必要があります。フォームの場合++、コンパイラーはショートカットを使用して、変数を所定の位置にインクリメントすることができます。

于 2011-12-23T10:43:57.407 に答える