K&R Ch 1:
このステートメント
++nc
は、新しい演算子を示し++
ます。これは、1ずつインクリメントすることを意味します。代わりに書くこともできますがnc = nc + 1
、++nc
より簡潔で、多くの場合、より効率的です。
プレインクリメントが代替よりも効率的であるのはいつですか?ほとんどの場合、少なくとも、両方のアセンブリはadd
(edit:またはinc
)命令です。それらはいつ違いますか?
K&R Ch 1:
このステートメント
++nc
は、新しい演算子を示し++
ます。これは、1ずつインクリメントすることを意味します。代わりに書くこともできますがnc = nc + 1
、++nc
より簡潔で、多くの場合、より効率的です。
プレインクリメントが代替よりも効率的であるのはいつですか?ほとんどの場合、少なくとも、両方のアセンブリはadd
(edit:またはinc
)命令です。それらはいつ違いますか?
そのテキストは古くなっています。70年代には、コンパイラが++ nに対してより効率的な出力を生成することは事実でしたが、それ以上は生成されませんでした。最新のコンパイラはすべて同じコードを生成します。
ほとんどの場合、少なくとも、両方のアセンブリはadd命令です。
それは完全には真実ではありません。多くの場合、個別の「1つずつインクリメント」命令があります。ただし、半ばまともなコンパイラはとに対して同一のマシンコードを生成するため、これは関係ありませ++nc
んnc = nc + 1
。
つまり、パフォーマンスの違いはありません。この本が書かれたとき、コンパイラーはあまり良くなかったかもしれませんが、もうありません。
確かなことはわかりませんが、私はただ声を出して考えています(多分私はすべきではありません):おそらくK&Rの時代に、++nc
より効率的なものにコンパイルされましたnc = nc + 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
>
「通常の」変数の場合、他の回答が示唆するように違いはないはずです。資格がある場合にのみ、結果が異なる可能性がありnc
ます。voloatile
このような変数の場合、+1
フォームは最初nc
にロードされている式を評価してnc
から、加算を実行する必要があります。フォームの場合++
、コンパイラーはショートカットを使用して、変数を所定の位置にインクリメントすることができます。