web-dev-qa-db-ja.com

while(1)の目的; Cのステートメント

while(1);の目的は何ですか? while(1)(セミコロンなし)は無限ループであり、スピンロックの状況に似ています。ただし、while(1);を使用できる場所がわかりません。

サンプルコード

_if(!condition)
{ 
  while(1);
}
_

注:これは、do-while()またはプレーンwhile(1)の場合ではありません。

54
Abhijit K Rao

言語のすべての有効なステートメントは、目的にかなわないでないことに注意してください。それらは言語の文法に従って有効です。 if (1);など、多くの同様の「役に立たない」ステートメントを作成できます。このようなステートメントは、条件付き(ifwhileなど)と空のステートメント_;_(明らかに特定の機能はありませんが、有効なステートメントでもあります)目的)。

そうは言っても、セキュリティコードでwhile (1);に遭遇しました。ユーザーが組み込みデバイスで非常に悪いことをするとき、他の何かを試みるのをブロックするのは良いことです。 while (1);を使用すると、認定オペレーターが手動でデバイスを再起動するまで、無条件にデバイスをブロックできます。

while(1);は、カーネルパニックの実装の一部である場合もありますが、for(;;) {}ループは無限ループを表現するより一般的な方法のようで、空でない場合がありますbody(たとえば panic_blink() )に。

87
dureuill

アセンブリを掘り下げてみると(組み込みシステムの観点から理解しやすい、またはブートローダーをプログラムしようとした場合)

whileループは単なるjmp命令であることがわかります。

(pseudo code: starting loop address)
add ax, bx
add ax, cx
cmp ax, dx
jz  (pseudo code: another address location)
jmp (pseudo code: starting loop address)

これがどのように機能するかを説明しましょう。プロセッサは、命令に関係なく、順番に実行を続けます。したがって、このループに入ると、レジスタbxをaxに追加してaxに保存し、レジスタcxをaxに追加してax、cmp ax、dxに保存します(これはaxからdxを減算することを意味します)jz命令は(別のアドレスにジャンプすることを意味します位置)ゼロフラグが設定されている場合(これは、上記の減算の結果がゼロの場合に設定されるフラグレジスタのビットです)、jmpを開始ループアドレスに(かなり簡単に)、すべてをやり直します。

私がこのすべてのアセンブリであなたを悩ませた理由は、これがCで翻訳されることをあなたに示すためです

int A,B,C,D;
// initialize to what ever;

while(true)
{
A = A + B;
A = A + C;

if((A-D)==0)
{break;}

}

// if((X-Y)==0){break;} is the 
// cmp ax, dx
// jz  (pseudo code: another address location)

したがって、あるセクションを繰り返したり、新しいプログラムをロードしたり、何かを実行したりするためにjmp(whileループ)で終わらない非常に長い命令のリストがある場合、アセンブリのシナリオを想像してください。最後の命令を実行し、次の命令をロードして何も検出しません(その後、フリーズまたはトリプルフォールトなどが発生します)。

そのため、イベントがトリガーされるまでプログラムに何もさせたくない場合は、while(1)ループを使用する必要があります。これにより、プロセッサーはその場所でジャンプし続け、空の命令アドレスに到達しません。イベントがトリガーされると、イベントハンドラーの命令アドレスにジャンプして実行し、割り込みをクリアして、さらに割り込みを待機している場所にジャンプするwhile(1)ループに戻ります。 Btw the while(1)は、それについてさらに読みたい場合、スーパーループと呼ばれます...この時点で否定的に議論しコメントするのがめちゃくちゃかゆい人にとっては、これはアセンブリチュートリアルでも講義でもありません。それは可能な限り簡単な英語のわかりやすい説明であり、ポインターやスタック、その他などの基礎となる多くの詳細を見落とし、場合によっては物事を単純化してポイントを獲得します。ここでドキュメントの正確さを求めている人はいませんし、このCコードはこのようにコンパイルされないことを知っていますが、これはデモ専用です!!

29
a.atlam

これにはCというタグが付いていますが、C++の観点から始めます。 C++ 11では、コンパイラはwhile(1);を自由に最適化できます。

C++ 11ドラフト標準n3092、セクション6.5段落5(強調鉱山)から:

Forステートメントの場合のfor-init-statementの外側のループ。
—ライブラリI/O関数を呼び出しません。
—揮発性オブジェクトにアクセスしたり、変更したりしません。
—同期操作(1.10)またはアトミック操作を実行しません(29節)
は、実装によって終了すると想定される場合があります。 [注:これは、終了を証明できない場合でも、空のループの削除などのコンパイラー変換を許可することを目的としています。—終了注]


C11標準には同様のエントリがありますが、重要な違いが1つあります。 C11ドラフト標準n1570から(強調鉱山):

制御式が定数式ではない反復ステートメント、156) 入出力操作を実行せず、揮発性オブジェクトにアクセスせず、その本体、制御式、または(forステートメントの場合)そのexpression-3、実装によって終了すると想定される場合があります。157)
156)省略された制御式は、定数式であるゼロ以外の定数に置き換えられます。
157)これは、終了が証明できない場合でも、空のループの削除などのコンパイラー変換を許可することを目的としています。


これは、while(1);がC++ 11で終了するが、C11では終了しないと想定できることを意味します。それでも、一部のベンダーは、ノート157(バインドではない)を使用して、その空のループを削除できると解釈しています。 C++ 11とC11のwhile(1);の違いは、定義済み動作と未定義動作の違いです。ループは空なので、C++ 11で削除できます。 C11では、while(1);は終了しないことが証明されており、未定義の動作です。プログラマーはUBを呼び出しているため、コンパイラーは、問題のループの削除など、何でも自由に実行できます。

while(1);を削除するコンパイラーの最適化に関する多くのスタックオーバーフローの議論がありました。たとえば、 コンパイラは無限ループを排除できますか?スリープとして使用される空のforループは最適化されますか?「while( 1); "C++ 0x で。最初の2つはC固有であることに注意してください。

18
David Hammen

組み込みソフトウェアの使用法は、ウォッチドッグを使用してソフトウェアリセットを実装することです。

while (1);

または同等ですが、意図がより明確になるため安全です:

do { /* nothing, let's the dog bite */ } while (1);

ウォッチドッグが有効でxミリ秒後に確認されない場合、プロセッサをリセットすることがわかっているため、これを使用してソフトウェアリセットを実装します。

8
ouah

while(1);doループに関連付けられていないことを想定しています...

私が見たwhile(1);の唯一有用な実装は、割り込みを待っているdo-nothingループです。子プロセスが終了したことを示す、SIGCHLDを待機している親プロセスなど。すべての子プロセスが終了した後、親のSIGCHLDハンドラーは親スレッドを終了できます。

それはトリックを行いますが、多くのCPU時間を無駄にします。このような使用法では、プロセッサを定期的に放棄するために、おそらく何らかのスリープを実行する必要があります。

8

while(1);を見た場所の1つは、組み込みプログラミングです。

このアーキテクチャでは、メインスレッドを使用してイベントを監視し、ワーカースレッドを使用してイベントを処理しました。一定時間後にモジュールのソフトリセットを実行するハードウェアウォッチドッグタイマー(説明 ここ )がありました。メインスレッドポーリングループ内で、このタイマーをリセットします。メインスレッドが回復不能なエラーを検出した場合、while(1);を使用してメインスレッドを結び付け、ウォッチドッグリセットをトリガーします。 assertエラーはwhile(1);でも実装されたと思います。

5
waldol1

他の人が言ったように、それはまったく何もしない無限ループであり、完全に類似しています

while (1) {
    /* Do nothing */
}

セミコロンを含むループには本体があります。ステートメントとして使用する場合、単一のセミコロンはnullステートメントであり、ループ本体はそのnullステートメントで構成されます。

読みやすくするため、nullステートメントがループの本体であることを読者にわかりやすくするために、別の行に記述することをお勧めします。

while (1)
    ;

そうしないと、通常はセミコロンがない「while」行の終わりで見逃しやすくなり、読者は次の行をループの本体と間違える可能性があります。

または、代わりに空の複合ステートメントを使用します。

_while(1);
_

実際に非常に便利です。特に、それが何らかのパスコードなどを持っているプログラムであり、たとえば、ユーザーが間違ったパスコードを3回入力したためにユーザーのプログラムの使用を無効にしたい場合。 while(1);を使用すると、プログラムの進行が停止し、主にセキュリティ上の理由から、プログラムが再起動されるまで何も起こりません。

1
Zach P

これは Interrupt を待つために使用できます。基本的に、必要なものをすべて初期化し、何かが起こるのを待ちます。その後、特定の関数が呼び出されて実行され、その後待機状態に戻ります。

そのことは、ボタンを押す、マウスクリック/移動、受信したデータなどです。

さらに言えば、UIフレームワークではsimilarものが実際によく使用されます。ユーザーのアクションに関するシグナルを待機している間。

1
ST3

AVRチップセットプログラミング(Cプログラミング言語を使用)では、このステートメントが頻繁に使用され、イベントループのような役割を果たします。

カウントアップカウンターを設計する場合、このコードを使用して実装できます。

void interrupt0() {
   /* check if key pressed, count up the counter */
}

void main() {
    /* Common inits */
    /* Enable interrupt capability and register its routine */

    /* Event loop */
    while(1);
} 
1
frogatto

条件は常に真であるため、数学で知られている論理トートロジーを使用していると言えます。ループは常に真であることが証明されていますが、コードによって強制されない限り、またはリソースが崩壊するまで、ループは停止しません。

0

while(1);が使用される理由は、コードの早い段階でこのハンドラーにEventHandlerまたは割り込みが設定されているためだと思います。コードが非常に短い時間だけ「待機」することがわかっている場合、標準のスレッドセーフロックコードを使用すると、かなり時間がかかります。したがって、while(1);を使用して割り込みと「スピン」を設定できますが、これはビジー待機(CPUアイドル/他のスレッドのサービスを許可しない)であるにもかかわらず、設定に非常に少ないサイクルを要します。

要約すると、スレッドが割り込みまたはイベントを待機している間の「安い」スピンロックです。

0
Th3Minstr3l