「for(;;)」は「while(TRUE)」よりも高速ですか?そうでない場合、なぜ人々はそれを使うのですか?


164
for (;;) {
    //Something to be done repeatedly
}

こういうのがよく使われているのを見てきましたが、なかなかおかしいと思いますが…とか、そういうふうに言った方がわかりやすいと思いませんwhile(true)か?

私は(プログラマーの多くが暗号コードに頼る理由と同じように)これがわずかなマージンであると思っていますか?

なぜ、そしてそれは本当に価値があるのでしょうか?もしそうなら、なぜそれをこのように定義しないのですか:

#define while(true) for(;;)

参照:どちらが速いか:while(1)またはwhile(2)?


51
TRUE??? とは
AnT 2010

20
@Steven Sudit:TRUEC とは何の関係があるのですか?C99での真のブール結果の標準マクロはまだtrueです。どこTRUEから来たのですか?
AnT

31
そのマクロは仕事は、しません#define EVER ;;... :)かかわらIOCCCで使用されてきた

18
#define while(TRUE)呼び出されTRUEた1つの引数を取るマクロを宣言するためのそのマクロは使用されないため、プログラム内のすべてのwhileループを無限ループに変換しませんか?
AshleysBrain、2010

9
@Steven Sudit:いいえ。「VS 6.0の標準マクロ」はありません。マクロTRUEは、Windows APIに関連付けられたヘッダーファイルから取得されます。VS 6.0とはまったく関係ありません。そして、前に言ったように、それはCやC ++とは何の関係もありません。C ++では、「真の」リテラルはtrue(VS 6.0でも)ちょうどですが、C89 / 90ではまったくそのようなものはなく、C99ではマクロtrueです。これはすべてのC / C ++コンパイラに適用されます。
AnT

回答:


262
  1. 速くはありません。
  2. 本当に気になる場合は、プラットフォームのアセンブラ出力を使用してコンパイルし、確認してください。
  3. それは問題ではありません。これは重要ではありません。無限ループを好きなように書いてください。

227
直感的に、無限ループを最適化すると、無限にスピードアップする可能性があります。直感でプログラミングしないのは良いことです。:-)
Steven Sudit、2010

5
私はあなたが正しいと思います。ささいなことについての「宗教的な」議論に巻き込まれていたと思います。良心を揺さぶってくれてありがとう。:D
Chris Cooper

6
@Steven LOL、それは興味深いですが、無限のスピードアップの可能性に実際に到達した唯一のシナリオは、ループが中断せずに本当に無限に実行される場合であり、これはおそらくバグであるか、意図されている場合、それがその可能性に達する前に無限の待機。
AaronLS 2010

7
@クリス。人生と同じようにプログラミングでは、宗教的な議論は本当に重要なことについてはあなたの時間に値するだけです。これはそれらの1つではありません。あなたが見ることができるように、誰もが終わりのないループを書くペットの方法を持っています。ささいなことで最も幸せになるものを自分で選び、重要なコードでプロファイラーを実行します。:)
ベンゾット

3
一部のプラットフォームの一部の初期のコンパイラは定数をロードし、それを条件付きでジャンプしたので、それは問題でした。当時はハードウェアでした。
peterchen

176

for(;;)は2つの理由で好みます。

1つは、一部のコンパイラで警告が生成されることですwhile(true)(「ループ条件が一定」など)。警告を回避することは常に良いことです。

もう1つは、for(;;)より明確でわかりやすいと思います。無限ループが欲しい。文字通り条件はありません、何にも依存しません。私はそれから抜け出すために何かをするまで、それを永遠に続けたいだけです。

それに対してwhile(true)、まあ、何が真実なのでしょうか?私は、trueがfalseになるまでループすることに興味がありません。これは、このフォームが文字通り言っていることです(true while trueがループします)。ループしたいだけです。

いいえ、パフォーマンスの違いはまったくありません。


73
警告を回避するための+1。しかし、明快さに関しては、この文脈よりも明確であることがわかります。その側面は個人的な好みに帰着するだけだと思います。
Tim

14
うん、好みと習慣。に慣れていない場合for(;;)は、明らかに奇妙に見えます。しかし、これ一般的なイディオムであり、またそれに遭遇することになるので、それに慣れるように試みることをお勧めします。;)
10

7
それが慣用的であるというjalfのコメントは本当にここでの答えです。これ、Cで「無限ループ」を記述する一般的な方法であるため、「無限ループ」で一般的に使用されます。イディオムに正当な理由がある必要はありません。これは、単なる自己強化規則です。
ca

7
@Steve:私は思います私はなぜ表示されない、これまで使用しますfor(;condition;)。それが、whileループの目的です。しかし、私のような無限ループで、私は本当にコンパイラは比較したくない、と述べたいずれかの条件を。単純には、とwhileループ、それはテストする必要があるだろうtrue、すべての反復を(いなくても非常識なコンパイラはそれを行うだろう、明らかに、それは気に私。それはあなたのコードをしすぎとして私を打つという原則だ)している間、for(;;)あなたは文字通り言っています「テストする条件はありません。ループするだけです。」私はそれがあなたの想像に最も近いものだと思いますloop {...}
jalf

32
while(true)警告が出された場合、コンパイラはサックします。
アルバート、

56

個人的にはfor (;;)数字が入っていないので、キーワードにすぎません。私はそれを好むwhile (true)while (1)while (42)while (!0)などなど


38
0、1、および無限大は許容可能なマジックナンバーであり、0と1をfalseに拡張すると、trueは損失ではありません。 truefor魔法のキーワード以上の魔法の番号ではなくfor(;;)、暗黙の魔法の無限大を使用します。(while (42)確かに嫌悪者です。)

38
正接:私のCS教授の1人が「プログラミングには0、1、nの3つの数値しかありません。それ以外のものはすべてマジックナンバーと呼ばれます」と述べました。
Ben Zotto

21
while(42)は最もクールで、while(1)、while(true)、while(!0)に関して異なる結果を生成せず、哲学的な意味を持っています。for(;;)とにかく、他の構文解析よりも高速に解析されると思います
ShinTakezou

2
@ShinTakezouの方がずっといいです#define LIFE 42 while (LIFE):)
mr5

1
まあwhile(true)何も含まれていません。and(;;)はキーワードではありません
RiaD '26 / 07/26

49

デニス・リッチーのために

  • それがfor (;;)デニス・リッチーがK&Rでそれをする方法であり、新しい言語を学ぶとき、私はいつも賢い人を真似ようとするので、私は使い始めました。

  • これは慣用的なC / C ++です。C / C ++スペースで多くのことを計画している場合は、長期的には慣れる方が良いでしょう。

  • あなたの#define事は#1 define'dされて以来の意志ではない仕事は、C識別子に見えるように持っています。

  • 最新のコンパイラはすべて、2つの構成要素に対して同じコードを生成します。


10
はい、これは、誰かがK&RからCを学んだことを知る方法です。私が見たときはいつでもwhile(TRUE)、プログラマーはCの初心者か、For Dummiesの本からCを学んだのではないかと思います。
クリストファージョンソン2010

13
これらの初心者もnewfangled関数定義スタイルを使用していると聞いています。
ジャスティン

46

それは確かにどの正気なコンパイラでも速くはありません。それらは両方とも無条件ジャンプにコンパイルされます。forバージョンは(Neilが言ったように)入力しやすく、forループ構文を理解すれば明確になります。

興味があれば、ここにgcc 4.4.1がx86用に提供するものを示します。どちらもx86 JMP命令を使用します。

void while_infinite()
{
    while(1)
    {
    puts("while");
    }
}

void for_infinite()
{
    for(;;)
    {
    puts("for");
    }
}

(一部)にコンパイルします。

.LC0:
.string "while"
.text
.globl while_infinite
    .type   while_infinite, @function
while_infinite:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
.L2:
    movl    $.LC0, (%esp)
    call    puts
    jmp .L2
    .size   while_infinite, .-while_infinite
    .section    .rodata
.LC1:
    .string "for"
    .text
.globl for_infinite
    .type   for_infinite, @function
for_infinite:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
.L5:
    movl    $.LC1, (%esp)
    call    puts
    jmp .L5
    .size   for_infinite, .-for_infinite

デバッグモードでも高速だとは思いません。
Steven Sudit、2010

106
for_infinite高速です。に2文字少ないputs
Dave Jarvisが

43

for (;;)Cライクなさまざまな言語で最も一貫性があるので、私は好みます。

C ++ではwhile (true)問題trueありませんTRUEが、Cでは定義するヘッダーに依存していますが、一般的に使用されるマクロでもあります。あなたが使用している場合while (1)には、CやC ++、およびJavaScriptで正しいのですが、ないJavaやC#、ブール値であることをループ条件を必要とする、などwhile (true)while (1 == 1)。PHPでは、キーワードは大文字と小文字を区別しませんが、言語は大文字を優先しますTRUEます。

ただし、for (;;)これらのすべての言語で常に完全に正しいです。


9
ご回答有難うございます!これは実際には、より良い客観的な方法を示す最初の答えだと思いますfor (;;)
Chris Cooper、

8
C、C ++、JavaScript、Java、およびC#で正しいコードを書く必要はないと思います。それらは異なる言語です。
キース・トンプソン

6
@KeithThompsonそれは多くの言語で正しいコードを書くことではありません。私は、背景が異なる開発者間の誤解を回避することだと思います。
マウロサンピエトロ2014

6
@sam:while (1)for (;;)は両方とも、Cの無限ループの一般的なイディオムです。どちらかを理解できないCプログラムを読んでいる人は、コードの残りの部分で問題が発生する可能性があります。これは、簡単にC.を知らない人が読み取り可能なCコード記述する価値はありません
キース・トンプソン

6
@KeithThompson Cの有能な読者は両方のイディオムに精通しているはずですが、これは作家がポリグロットプログラマである場合にも役立ちます。私の最後の仕事では、JS、ActionScript、およびPHPを日常的に使用し、コードの記述方法を統一すると(そうすることが理にかなっている場合)、プログラミングがより速くなり、保守が容易になります。
イオノクラストブリガム2014

21

私は個人的にfor (;;)イディオムを好みます(それは同じコードにコンパイルされます)while (TRUE)ます)。

while (TRUE)ある意味で使用する方が読みやすいかもしれませんが、目立つfor (;;)ため、私はイディオムを使用することにしまし

無限ループ構造を簡単に気づいたか、アウトと呼ばれるコードでは、と私は個人的に考えるべきであるfor (;;)スタイルは、このビットよりも優れていwhile (TRUE)たりwhile (1)

また、whileループの制御式が定数の場合、一部のコンパイラが警告を発行することを思い出しました。私はそれがあまり起こらないと思いますが、偽の警告の可能性だけでそれを避けたいと思うのに十分です。


17

このような#defineがあるので、これを好む人がいるのを見たことがある。

#define EVER ;;

これにより、これを書くことができます:

for (EVER)
{
    /* blah */
}

24
私もそれを見てきました。しかし、それを選ぶ理由にはなりません。メンテナーとして、あなたはまだマクロ定義をチェックして、それがあなたが期待したことをしたことを確認する必要がありますが、元のコードは十分に明確でした。RTOS VxWorksにはマクロがFOREVER定義されていますがfor(;;)、それよりも優れています。IMOマクロは、新しい言語を「発明」するために使用すべきではありません。
クリフォード

8
実際、一部の言語のマクロの目的は、新しい構文を発明することです。しかし、C / C ++の 'for(EVER)'に関係なく厄介です。
Dan Olson、

15
一部の人々は、彼らがパスカルのように、彼らが言う場合のように、面白いことを行う#define BEGIN {#define END }#define DONKEYS_FLY (0)彼らが言うことができるように私も見たことがありますif DONKEYS_FLY ...。ソフトウェアは退屈だと誰が言うのですか?
Mike Dunlavey、2010

11
カリフォルニアでは私はあなたが#define for(;;)LIKE_FOREVER
Martin Beckett

1
私は抵抗できませんでした:#define never while(0)そして#define always
alfC 2013年

16

何について(あなたの言語がそれをサポートしているなら):

start:
/* BLAH */
goto start;

...妥当なコンパイラの手で同じ出力を生成するはずです。
Ben Zotto

9
+1!goto多数の欠点を改善するものではありませんが、実装しようとしているアルゴリズムがフローチャートからのものである場合、これは最も直接的な変換です。
エドモンド

4
私は個人的にgotoについて実用的な見方をしています。猛禽類はいません。猛禽類は人です。そして、gotoを使用してスパゲッティコードを作成し始めたのはこの人々でした。また、ループのアセンブルされた出力は、ほとんどこのように見えます。コンピュータの命令セットには「for」または「while」の概念はなく、「ジャンプ」のみです。
josaphatv 2013年

決して使用しないgoto
エドワードカラック14

本当に素晴らしい点gotobreak、ループを無限大にするために誰かがを追加することを心配する必要がないことです。(すでに別のループwhileまたはforもちろんループ内にいる場合を除いて...)

12

生成されるマシンコードの点で違いはありません。

ただし、傾向を打ち消すために、while(TRUE)フォームはfor(;;)よりはるかに読みやすく直感的であり、読みやすさと明確さは、コーディングガイドラインの重要な理由であり、あらゆる理由よりも重要です。 for(;;)アプローチについて聞いた(私は自分自身のコーディングガイドラインを確固とした推論および/または有効性の証明に自分で基づくことを好む)。


6
それはあなたの言語に依存します。for(;;)これは、CおよびC ++でこれを行う従来の方法です。while(true)C#やJava、その他の言語での慣習のようです。あなたのマイレージは異なる場合があります。
ビリーONeal

9
はい、CまたはC ++に精通していない人はsscanfよりもSTRING_SCAN_FORMATTEDの方が読みやすいかもしれませんが、#define STRING_SCAN_FORMATTED sscanfをコードの先頭に配置している人はいないでしょう。
ta.speot.is 2010

4
それを行う慣用的な方法は、開発者にとって最も読みやすいものであるいいと思います。それ以外の場合は、本当に優れた開発者が必要です。
2010

5
@despart:誰かがC ++に慣れておらず、そのイディオムが何であるかを認識できない場合は、私のコードベースから遠ざける必要があります。
ビリーONeal

4
私は慣用的な方法が最も読みやすいはずであることに同意します。そのため、言語や慣習が進化するにつれて、慣用的な方法に常に挑戦し、変更する必要があります。恐ろしいK&Rの「慣用的」なコーディングスタイルが、よりモダンで読みやすいスタイルに置き換わるのに何年もかかりましたが、それでも起こりました。
Jason Williams


11
while(true)

Visual Studioで警告を生成します(条件は一定です)。私がこれまでに行ったほとんどの場所では、警告をエラーとして生成ビルドをコンパイルします。そう

for(;;)

優先されます。


7
どのバージョンのビジュアルスタジオを使用していますか?2008では、警告レベル4であっても、この警告は表示されません。
JörgenSigvardsson

11

コードがコンパイラーによって最適化されている場合、両方とも同じでなければなりません。最適化の意味を説明するために、MSVC 10で記述されたサンプルコードを次に示します。

int x = 0;

while(true) // for(;;)
{
    x +=1;

    printf("%d", x);
}

デバッグモード(最適化なし(/ Od)なし)でビルドした場合、逆アセンブリは明確な違いを示します。true内部の状態に関する追加の説明がありますwhile

while(true)
00D313A5  mov         eax,1                //extra 
00D313AA  test        eax,eax              //extra
00D313AC  je          main+39h (0D313B9h)  //extra
    {
        x +=1;
00D313AE  mov         eax,dword ptr [x]  
00D313B1  add         eax,1  
00D313B4  mov         dword ptr [x],eax  
    printf("%d", x);
    ...
    }
00D313B7  jmp         main+25h (0D313A5h)  


for(;;)
    {
        x +=1;
00D213A5  mov         eax,dword ptr [x]  
00D213A8  add         eax,1  
00D213AB  mov         dword ptr [x],eax  
    printf("%d", x);
    ...
    }
00D213AE  jmp         main+25h (0D213A5h)  

ただし、コードをリリースモード(デフォルトの最大速度(/ O2)で)でビルドすると、両方で同じ出力が得られます。両方のループが1つのジャンプ命令に削減されます。

for(;;)
    {
        x +=1;
01291010  inc         esi  

        printf("%d", x);
    ...
    }
0129101C  jmp         main+10h (1291010h)  

    while(true)
    {
        x +=1;
00311010  inc         esi  

        printf("%d", x);
    ...
    }
0031101C  jmp         main+10h (311010h)  

速度の最適化がオンになっているまともなコンパイラーでは、どちらを使用してもかまいません。


これは実際には非常に良い点です!最適化を行わないと、最新のコンパイラでもいくつかの命令が異なります。

9

どちらが速いかは個人の好みの問題です。個人的には、私はタッチタイピストであり、プログラミング中にキーボードを見ることはありません-キーボードの104個すべてのキーをタッチタイプできます。

「while(TRUE)」と入力した方が速いかわかります。

いくつかの指の動きの測定値を精神的に追加し、それらを合計しました。「for(;;)」は前後に12のキー幅の移動があります(ホームキーとキーの間、およびホームキーとSHIFTキーの間)「while(TRUE)」には約14のキー幅の移動と第4。

ただし、後者を入力するときにエラーが発生しにくくなります。私は一度に精神的に言葉で考えるので、「nIdx」などの頭字語よりも「nIndex」のようなものを入力する方が、心の中で話すよりも実際に文字を頭の中で綴り、指を自動で聞かせる必要があるので、早く見つけます。 -単語を入力します(自転車に乗るような)

(私のTypingTest.comベンチマーク= 136 WPM)


3
OPはタイピング速度ではなく、ランタイム速度を参照していたと思います。

知っている。そのベースもカバーしなければなりませんでした。
Mark Rejhon、2010

7
s /個人の好み/個人の習慣/
SamB

@SamB:s ///へのコメントの投票。xDそして、はい、それはランタイム速度が原因である可能性があることを示唆しましたが、実際の答えは知りませんでした。これなら、私は幸せだったでしょう。
Chris Cooper、

を実行しtime head -10 >/dev/null、それぞれを10回入力して、結果を測定します。for(;;)あなたがカンニングしない限り、あなたはより速くなるでしょう。約14%でした。
PSkocik 2015

6

すべての良い答え-動作はまったく同じでなければなりません。

ただし、違いがあったと仮定してください。それらの1つが反復ごとに3つの命令をさらに処理したとします。

気にしますか?

ループ内で行うことがほとんど何もない場合にのみ、これはほとんどの場合当てはまりません

私のポイントは、ミクロの最適化とマクロの最適化があるということです。ミクロの最適化は、「散髪して減量する」ようなものです。


3
どのくらいの頻度で人々が優先++iするように言われるのを見i++ますか
Dennis Zickefoose

7
@Dennis Zickefoose:との違いは++ii++i組み込みではなくクラスのインスタンスであり、コンパイラが簡単な最適化を適用していない場合、重要になる可能性があります。アドバイスは、それが数えるときにあなたを捕まえないように習慣を身につけることです。
クリフォード

5
++ivs についてのi++ことは、「最適化」を行うために何も費用がかからないということです。確かに、ほとんどの場合、まったく違いはありませんが、タイプするのも同様に簡単です。そのため、デフォルトで最も効率的な可能性を優先しないのはなぜですか。ここでも同じことが当てはまると思います。一方がもう一方よりも少し高速だった場合、より高速なものを試してみませんか?それを行うことで何を失うでしょうか?どちらもかなり読みやすく、入力も簡単です。
2010

2
@Dennis Zickefoose:その通りです。SOについては多くのことがわかりますが、クリフォードのコメントは正しいです。さらに、SOではあまりられないものがあります。それ、43 倍のスピードアップのように、マクロ最適化を行う方法です:stackoverflow.com/questions/926266/…。だから私たちの優先事項について疑問に思います。
Mike Dunlavey、

2
@マイク:ええ、でもそれはリンゴとオレンジの比較です。散髪をすることは実際の時間、そしておそらくお金さえかかります。私はそれが本当に重要ではないほどのミクロ最適化であることに同意します。しかし、それも私たちに何の費用かかりません。左または右に行くことを選択でき、距離が同じで、地形が同じで、すべてが同じである場合、左のパスに微視的な利点があることを除いて、左に移動しないのはなぜですか?あなたは正しい、それは印象的な議論ではありません。しかし、コストが文字通りゼロの場合、最適ではないルートを選択する理由はわかりません。
2010

5

価値のあるコンパイラが異なるコードを生成することは想像できません。たとえそうであっても、より効率的な特定のコンパイラをテストせずに判断する方法はありません。

ただしfor(;;)、次の理由からお勧めします。

  • 私が使用した多くのコンパイラーは、適切な警告レベル設定でwhile(true)の定数式警告を生成します。

  • あなたの例では、マクロTRUEが期待どおりに定義されていない可能性があります

  • 無限の多くの可能なバリエーションがありますwhileループのようなwhile(1)while(true)while(1==1)など。そのためfor(;;)、整合性が向上する可能性があります。


TRUEは#define TRUE 1ではない可能性がありますが、while(TRUE)として評価されるコードベースでwhile(0)は、のメリットは得られませんfor(;;)
ジャスティン

@ジャスティン:私は同意します、それは本当にひねくれているでしょう、そしてそれは3つの引数の中で最も強力ではありませんが、Bjarne StoustrupはC ++でNULLマクロを回避するために同様の引数を使用します。while(true)いずれの場合も推奨されます。C ++ではbool予約されており、CではCで定義されています。stdbool.h(Cでは安全性が低くなります)。for(;;)すべての疑いを取り除きます。
クリフォード

5
for(;;Sleep(50))
{
    // Lots of code
}

より明確です:

while(true)
{
    // Lots of code
    Sleep(50);
}

これは、を使用していない場合には当てはまりませんSleep()


1
それはいまいましい悪いコードです、スリープの代わりにタイマーが使われるべきです、それでそれは悪い例です
ST3

12
@ ST3-はい、そうです。私のコードはひどいです。次に無限ループを作るときはもっと頑張るべきです。
Armada 2014年

1
@Frammo-OSに依存しますが、通常は次のようになりますtimerService.scheduleRepeating (50, [] () { /* lots of code */ });
Periata Breatta '11 / 11/16

2
そのようなforループ内でsleepのような関数を呼び出すことについて何もきれいなことはありません
Greg

1
OMG、timerService.scheduleRepeating(50、[](){})は、sleep(50)を入力して理解するほうがはるかに簡単です。
クールジャベリン2018

4

「永久」ループは、組み込みシステムでバックグラウンドループとして人気があります。一部の人々はそれを次のように実装します:

for (; ;)
{
 // Stuff done in background loop
}

そして時々それはとして実装されます:

while (TRUE /* or use 1 */)
{
 // Stuff done in background loop
}

そしてさらに別の実装は:

do
{
 // Stuff done in background loop
} while (1 /* or TRUE */);

最適化コンパイラは、これらのフラグメントに対して同じまたは類似のアセンブリコードを生成する必要があります。1つの重要な注意:これらのループは永久に続くため、ループの実行時間は大きな問題ではなく、処理セクションにより多くの時間が費やされます。


8
コンパイラーがそれらに対して異なるコードを生成する場合は、コンパイラーを破棄して、過去20年間から1つを取得するときです。
GManNickG 2010

5
「これらのループは永遠に行くので、ループの実行時間は大きな問題ではない」 -という音ので、私..に間違った
Blindy

3
@Blindy-間違っているため、懸念されるのは、ループロジックの処理に費やされたランタイムの割合、または有効な作業の単位あたりのループロジックの量であり、どちらも無限ループによって助けられない
Ben Voigt

3

while(true)はfor(;;)よりも読みやすいと思います - プログラマーがforループで何かを見落としているように見えます :)


スピードが気になります。特に、コードに無限に影響する最適化がある場合。
コワルスキー

2

「for(;;)」を使用する最も重要な理由は、探索的プログラミングを行うときに「while(TRUE)」を使用することへの恐怖です。"for"を使用して繰り返し回数を制御する方が簡単です。また、 "for"ループを無限に変換する方が簡単です。

たとえば、再帰関数を作成している場合、無限ループに変換する前に関数の呼び出し量を制限できます。

    for(int i=0;i<1000;i++) recursiveFunction(oneParam);

関数がわかったら、無限ループに変換します。

    for(;;) recursiveFunction(oneParam);

3
最初のループに構文エラーがあります(セミコロンがない)。
イェンス

3
ハ!これにより、for(;;);)のマイナス面を示す
Andrew
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.