1. ホーム
  2. c

[解決済み】Cの複数行マクロ:do/while(0) vs スコープブロック [重複]。

2022-04-11 21:56:32

質問

<ブロッククオート

重複の可能性があります。

マクロを定義するときにdo while(0)を使うとどうなるのですか?

C/C++のマクロで無意味なdo/whileやif/else文があることがあるのはなぜですか?

do { ... } while (0) 何の役に立つの?

C言語の複数行マクロで、do/while(0)ループの中に入っているようなものを見たことがあるのですが。

#define FOO \
  do {
    ♪Do_stuff_here ♪Do_stuff_here ♪Do_stuff_here
    ドゥモア・スタッフ
  } while (0)

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

#define FOO \
  { \
    ♪Do_stuff_here ♪Do_stuff_here ♪Do_stuff_here
    ドゥモア・スタッフ
  }

解決方法は?

アンドレイ・タラセビッチ氏は次のように説明しています。

  1. Google グループについて
  2. bytes.comで

[書式に若干の変更がありました。角括弧内に親書きの注釈を追加しました。 [] ].

<ブロッククオート

do/while'バージョンを使用する全体的なアイデアは、マクロを作成することです。 は、複合文ではなく、通常の文に展開されます。これは 関数型マクロと統一するためです。 は、あらゆる文脈で通常の関数を使用することができます。

次のようなコードスケッチを考えてみましょう。

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

ここで foobar は普通の関数です。ここで を置き換えることができます。 foo を上記のような性質のマクロ [名前 CALL_FUNCS ]:

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

さて、2番目のアプローチに従ってマクロが定義されている場合 (ただ {} ) は、もはやコンパイルされないでしょう。 のブランチ if が複合文として表現されるようになりました。そして を置く ; の後に、この複合ステートメントを追加すると、全体の if ステートメントを削除し、その結果 else という分岐があります(そのため、コンパイルエラーになります)。

この問題を解決する方法の1つは、「このディレクトリに ; の後に マクロを起動する。

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

これはコンパイルして期待通りに動作しますが、これでは均一ではありません。そこで よりエレガントな解決策は、マクロが通常の ステートメントに変換されることはありません。これを実現する一つの方法として マクロは次のようになります。

#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'バージョンを使用する全体的な考え方は、以下の通りです。 には、この最後の ; をマクロに組み込むことができます(理由は説明したとおりです)。 となります。)