[解決済み] コンパイラはdo-whileループと他のタイプのループの間でより良いコードを生成するか?
質問
の中にコメントがあります。 zlib 圧縮ライブラリ (Chromium プロジェクトや他の多くのプロジェクトで使用されている) にコメントがあり、C 言語の do-while ループはほとんどのコンパイラで "より良いコードを生成することを暗に示しています。以下は、そのスニペットが表示されるコードです。
do {
} while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
scan < strend);
/* The funny "do {}" generates better code on most compilers */
https://code.google.com/p/chromium/codesearch#chromium/src/third_party/zlib/deflate.c&l=1225
ほとんどの(あるいはすべての)コンパイラがより良い(例えばより効率的な)コードを生成するという証拠はあるのでしょうか?
更新してください。 マーク・アドラー は、原著者の一人である は、その背景を少し述べています。 をコメントで述べています。
どのように解決するのですか?
まず最初に
A
do-while
ループは
while
-ループまたは
for
-ループになります。
-
while
そしてfor
ループはループ本体を全く実行しないかもしれません。 -
A
do-while
ループは常にループ本体を少なくとも一度は実行します。つまり、初期状態のチェックをスキップします。
というわけで、論理的な違いです。とはいえ、誰もがこれを厳密に守っているわけではありません。よくあるのが
while
または
for
のループは、必ず一度はループすることが保証されている場合であっても、使用されることがあります。(特に
foreach
ループがある言語では特に)。
というわけで、リンゴとオレンジを比較しないように、ループは必ず一度は実行されるものと仮定して話を進めることにします。さらに、ここでは
for
ループは本質的に
while
ループであり、ループカウンターのための構文が少しあるためです。
というわけで、質問に答えます。
もし
while
ループが少なくとも一度はループすることが保証されているのであれば、ループの中に
do-while
ループを使用することでパフォーマンス上の利点はありますか?
A
do-while
は最初の条件チェックをスキップします。そのため、分岐が1つ減り、評価する条件も1つ減ります。
条件のチェックにコストがかかり、少なくとも1回はループすることが保証されているのであれば
do-while
ループの方が速いかもしれません。
そして、これはせいぜいマイクロ最適化と考えられていますが、コンパイラが常に行うことができないものです。特に、コンパイラがループが常に少なくとも一度は入るということを証明できない場合です。
言い換えれば、while-loopです。
while (condition){
body
}
は事実上これと同じです。
if (condition){
do{
body
}while (condition);
}
必ず一度はループすることが分かっていれば、if文は余計なお世話です。
同様にアセンブリレベルでも、異なるループがどのようにコンパイルされるかは大体このような感じです。
do-whileループ。
start:
body
test
conditional jump to start
while-loopです。
test
conditional jump to end
start:
body
test
conditional jump to start
end:
条件が重複していることに注意してください。別のアプローチとして
unconditional jump to end
start:
body
end:
test
conditional jump to start
... これは、重複するコードと追加のジャンプをトレードオフするものです。
いずれにせよ、これは通常の
do-while
ループよりも悪いことに変わりはありません。
とはいえ、コンパイラは好きなようにできる。そして、ループが常に一度だけ入ることを証明できれば、それはあなたのために仕事をしたことになります。
しかし、質問の特定の例では、ループのボディが空であるため、少し奇妙なことがあります。ボディがないので
while
と
do-while
.
参考までに、Visual Studio 2012でテストしてみました。
-
ボディが空の場合、実際に同じコードを生成して
while
とdo-while
. だからその部分は、コンパイラがそれほど優れていなかった昔の名残りだろう。 -
しかし、空でないボディで、VS2012 は条件コードの重複を避けることに成功しますが、それでも余分な条件ジャンプを生成します。
ですから、質問の例では、なぜ
do-while
ループが一般的なケースでより速くなり得る理由を強調している一方で、その例自体は最新のコンパイラでは何の利点も与えていないように見えるのは皮肉なことです。
このコメントの古さを考慮すると、なぜそれが問題になるのか推測することができます。当時のコンパイラーは、ボディが空であることを認識する能力がなかった可能性が非常に高いです。(または、認識できたとしても、その情報を使用しなかった)。
関連
-
error: 'for' loop initial declaration is only allowed in C99 mode 原因と解決方法
-
C/C++の再定義
-
[解決済み] Xcode - 警告。C99 では関数の暗黙の宣言は無効です。
-
[解決済み] mallocとcallocの違い?
-
[解決済み] longをフォーマットするprintfの引数は何ですか?
-
[解決済み] C言語でオブジェクト指向のコードを書くとしたら、どのようにすればよいのでしょうか?[クローズド]
-
[解決済み] C言語でファイルが存在するかどうかを確認する最も良い方法は何ですか?
-
[解決済み] C 言語の配列へのポインタ/ポインタの配列の曖昧さ解消
-
[解決済み] なぜalloca()の使用はグッドプラクティスとみなされないのでしょうか?
-
[解決済み] C言語で "unsigned long "をprintfする方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
C - 添え字の値が配列でもポインタでもベクトルでもないエラー
-
警告:符号付き整数式と符号なし整数式の比較 [-Wsign-compare]
-
[解決済み] stdinとSTDIN_FILENOの違いは何ですか?
-
[解決済み] c または c++ 用のシンプルな 2 次元クロスプラットフォームグラフィックスライブラリ?[クローズド]
-
[解決済み] C関数から文字列を返す
-
[解決済み] "static const" vs "#define" vs "enum"
-
[解決済み] C言語で関数をパラメータとして渡すにはどうすればよいですか?
-
[解決済み] while ( !feof (file) ) 」は、なぜいつも間違っているのですか?
-
[解決済み] プログラム終了前にmallocの後にfreeをしないと本当に何が起こるのか?
-
[解決済み] アセンブリがCより速いのはどんなとき?[クローズド]