208

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

次のような do/while(0) ループ内にラップされた複数行の C マクロを見てきました。

#FOOを定義\
  行う { \
    do_stuff_here \
    do_more_stuff \
  } ながら (0)

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

#FOOを定義\
  { \
    do_stuff_here \
    do_more_stuff \
  }
4

1 に答える 1

313

Andrey Tarasevich は、次の説明を提供します。

  1. Google グループで
  2. bytes.com で

【書式を一部変更しました。角括弧内に追加された括弧内の注釈[]]。

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

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

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

ここでfoobarは通常の関数です。ここで、 function を上記の性質 [named ]fooのマクロに置き換えたいと想像してください:CALL_FUNCS

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

{ここで、マクロが 2 番目のアプローチ ( andのみ)に従って定義されている場合}、コードはコンパイルされなくなりますif。そして、;この複合ステートメントの後に a を配置すると、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)。その定義の最後にa;を配置すると、'do/while' を使用するポイント全体が即座に無効になり、そのマクロは複合ステートメント バージョンとほぼ同等になります。

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

于 2009-07-01T04:11:14.980 に答える