浅谈ド{…}while(0)マクロ定义における役割


もしあなたがCプログラマであれば、マクロに詳しいはずです。それらは非常に強いです。正しい使い方をすれば、あなたの仕事は大変なことになります。しかし、マクロを定義する時、勝手にチェックしていないと、彼らはあなたを狂わせ、N時間を無駄にしてしまうかもしれません。多くのCプログラムでは、直接的ではないように見える多くのマクロ定義が見られます。
次はその例です。

#define __set_task_state(tsk, state_value)   \ 
  do { (tsk)->state = (state_value); } while (0) 
Linuxカーネルや他の有名なCライブラリには、do{…}while(0)を使用したマクロ定義がたくさんあります。このマクロの用途は何ですか?何かメリットがありますか?
GoogleのRobert Love(以前Linuxカーネル開発に従事していた)は次のように答えてくれます。
ド{…}while(0)はCで唯一の構造プログラムであり、定義されたマクロはいつも同じように動作します。これはどんなにマクロを使っても(特に大きな括弧で囲まれてマクロを呼び出す文がない)、マクロの後のセミコロンも同じ効果です。
この言葉はちょっと言いにくいかもしれませんが、実用的な一言で言えば、do{…}while(0)を使ったマクロ定義は、大かっこやセミコロンなどの影響を受けず、いつも希望通りに実行を呼び出されます。
たとえば:

#define foo(x) bar(x); baz(x) 
その後、このように呼び出すことができます。

foo(wolf); 

これはマクロによって拡張されます。

bar(wolf); baz(wolf); 
これは確かに私たちが望む正確な輸出です。以下を見てみます。このように呼んだら、

if (!feral) 
foo(wolf); 

拡張したらあなたが望む結果ではないかもしれません。上の文は次のように拡張されます。

if (!feral) 
bar(wolf); 
baz(wolf); 

明らかに、これは間違いであり、みんながよく犯しやすい間違いの一つでもある。
ほとんどの場合、多文宏大を書いて正しい結果を達成することは不可能です。マクロを関数のようにしてはいけません。do/while(0)がない場合。
もし私たちがdo{…}while(0)を使ってマクロを再定義したら、すなわち、

#define foo(x) do { bar(x); baz(x); } while (0) 

現在、この文の機能は前者に相当し、ドは大括弧内の論理が実行されることを保証し、while(0)はこの論理が一回だけ実行されることを確保することができます。すなわち、ループがない場合と同じです。
上のif文に対しては、次のように拡張されます。

if (!feral) 
do { bar(wolf); baz(wolf); } while (0); 

意味的には、以下の語句と等価である。

if (!feral) { 
  bar(wolf); 
  baz(wolf); 
} 

ここは困惑しているかもしれませんが、なぜ大きな括弧を使わずに直接マクロを取り囲むのですか?なぜdo/while(0)ロジックを使わなければならないですか?
例えば、大かっこでマクロを定義すると、次のようになります。

#define foo(x) { bar(x); baz(x); } 

これは上に挙げたif文に対して確かに正しく拡張されていますが、もし次のような文言があるならば、

if (!feral) 
  foo(wolf); 
else
  bin(wolf); 

マクロを拡張すると、次のようになります。

if (!feral) { 
  bar(wolf); 
  baz(wolf); 
}; 
else
  bin(wolf); 

これは文法が間違っていることが分かります。
まとめ:Linuxと他のコード庫のマクロは、いずれもdo/while(0)で実行ロジックを包囲しています。マクロの動作が常に同じであることを保証できます。コードを呼び出しても、何分間と大かっこを使っています。
以上の浅谈ド{…}while(0)は、マクロの定义での役割は、小编が皆さんに共有している内容の全てです。