一言で言えば(tl; dr):
私はOPのコードのコメントを少し異なって解釈しています。彼らが観察したと主張する「より良いコード」は、実際の作業をループの「条件」に移動したためだと思います。ただし、これはコンパイラ固有のものであり、わずかに異なるコードを生成することはできますが、以下に示すように、ほとんど無意味でおそらく時代遅れであることに完全に同意します。
詳細:
原作者はこれについての彼のコメントで何を意味するのかと言うのは難しいdo {} while
産より良いコードが、私はここで育てられたものよりも、別の方向に推測したい-私たちは、違いと信じているdo {} while
とwhile {}
、ループはかなり(スリム1本の以下の枝などでありますMysticalは言った)が、このコードには「おかしな」ものさえあり、それがすべての作業をこのクレイジーな状態の中に置き、内部部分を空のままにしています(do {}
)。
私はgcc 4.8.1(-O3)で次のコードを試してみましたが、興味深い違いがあります-
#include "stdio.h"
int main (){
char buf[10];
char *str = "hello";
char *src = str, *dst = buf;
char res;
do { // loop 1
res = (*dst++ = *src++);
} while (res);
printf ("%s\n", buf);
src = str;
dst = buf;
do { // loop 2
} while (*dst++ = *src++);
printf ("%s\n", buf);
return 0;
}
コンパイル後-
00000000004003f0 <main>:
...
; loop 1
400400: 48 89 ce mov %rcx,%rsi
400403: 48 83 c0 01 add $0x1,%rax
400407: 0f b6 50 ff movzbl 0xffffffffffffffff(%rax),%edx
40040b: 48 8d 4e 01 lea 0x1(%rsi),%rcx
40040f: 84 d2 test %dl,%dl
400411: 88 16 mov %dl,(%rsi)
400413: 75 eb jne 400400 <main+0x10>
...
;loop 2
400430: 48 83 c0 01 add $0x1,%rax
400434: 0f b6 48 ff movzbl 0xffffffffffffffff(%rax),%ecx
400438: 48 83 c2 01 add $0x1,%rdx
40043c: 84 c9 test %cl,%cl
40043e: 88 4a ff mov %cl,0xffffffffffffffff(%rdx)
400441: 75 ed jne 400430 <main+0x40>
...
したがって、最初のループは7つの命令を実行し、2番目のループは6つの命令を実行しますが、同じ作業を行うことになっています。今、私はこれの背後にコンパイラのスマートさがあるのかどうかは本当にわかりません、おそらくそれは偶然ではありませんが、このプロジェクトが使用している他のコンパイラオプションとどのように相互作用するのかは確認していません。
一方、clang 3.3(-O3)では、両方のループが次の5つの命令コードを生成します。
400520: 8a 88 a0 06 40 00 mov 0x4006a0(%rax),%cl
400526: 88 4c 04 10 mov %cl,0x10(%rsp,%rax,1)
40052a: 48 ff c0 inc %rax
40052d: 48 83 f8 05 cmp $0x5,%rax
400531: 75 ed jne 400520 <main+0x20>
これは、コンパイラがまったく異なり、数年前に一部のプログラマが予想したよりもはるかに速い速度で進んでいることを示しています。また、このコメントはかなり意味がなく、おそらく意味があるかどうかを誰も確認したことがないため、おそらくそこにあります。
結論-可能な限り最高のコードに最適化したい場合(そしてコードがどのように見えるかを知っている場合)、それをアセンブリーで直接実行し、方程式から「中間者」(コンパイラー)をカットしますが、その新しいものを考慮に入れますコンパイラと新しいHWは、この最適化を廃止する可能性があります。ほとんどの場合、コンパイラーにそのレベルの作業を任せて、大きなものの最適化に集中する方がはるかに優れています。
もう1つ注意すべき点は、命令カウント(これが元のOPのコードの後にあったものと想定)は、コードの効率を測定するための優れた手段ではありません。すべての命令が同等に作成されたわけではなく、それらの一部(たとえば、単純なregからregへの移動)は、CPUによって最適化されるため、非常に安価です。他の最適化は実際にはCPUの内部最適化に悪影響を与える可能性があるため、最終的には適切なベンチマークのみがカウントされます。