web-dev-qa-db-ja.com

C複数行マクロ:do / while(0)vs scopeブロック

可能な重複:
マクロを定義するときにdo while(0)を使用するとどうなりますか?
C/C++マクロにdo/whileおよびif/elseステートメントが無意味になることがあるのはなぜですか?
{…} while(0)それは何のためですか?

Do/while(0)ループ内にラップされた複数行のCマクロを見ました:

#define FOO\
 do {\ 
 do_stuff_here\
 do_more_stuff\
} while(0)

基本的なブロックを使用するのではなく、そのようにコードを書くことの利点は(もしあれば):

#define FOO\
 {\ 
 do_stuff_here\
 do_more_stuff\
} 
170
krasnaya

http://bytes.com/groups/c/219859-do-while-0-macro-substitutions

アンドレイ・タラセビッチ:

「do/while」バージョンを使用するという考えは、複合ステートメントではなく通常のステートメントに展開されるマクロを作成することです。これは、すべてのコンテキストで通常の関数を使用して、関数スタイルマクロの使用を統一するために行われます。

次のコードスケッチを検討してください

if (<condition>)
  foo(a);
else
  bar(a);

ここで、「foo」と「bar」は通常の関数です。ここで、関数「foo」を上記の性質のマクロに置き換えたいと想像してください。

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

マクロが2番目のアプローチ(「{」と「}」のみ)に従って定義されている場合、「if」の「true」ブランチが複合ステートメントで表されるため、コードはコンパイルされなくなります。そして、「;」を入れるとこの複合ステートメントの後、「if」ステートメント全体を終了し、「else」ブランチを孤立させます(コンパイルエラーが発生します)。

この問題を修正する1つの方法は、「;」を入れないことを覚えておくことです。マクロ「呼び出し」の後

if (<condition>)
  CALL_FUNCS(a)
else
  bar(a);

これは期待どおりにコンパイルおよび動作しますが、これは均一ではありません。よりエレガントな解決策は、マクロが複合ステートメントではなく、通常のステートメントに展開されるようにすることです。これを達成する1つの方法は、次のようにマクロを定義することです

#define CALL_FUNCS(x) \
do { \
  func1(x); \
  func2(x); \
  func3(x); \
} while (0)

今、このコード

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

問題なくコンパイルされます。

ただし、CALL_FUNCSの私の定義とメッセージの最初のバージョンとの小さなながらも重要な違いに注意してください。 } while (0)の後に;を付けませんでした。 ;をその定義の最後に置くと、 'do/while'を使用するポイント全体がすぐに無効になり、そのマクロは複合ステートメントバージョンとほぼ同等になります。

元のメッセージで引用したコードの作者がwhile (0)の後にこの;を置いた理由がわかりません。この形式では、両方のバリアントが同等です。 'do/while'バージョンを使用する背後にある全体のアイデアは、この最後の;をマクロに含めないことです(上記で説明した理由のため)。

251
caskey