395

重複の可能性:
C/C++ マクロに無意味な do/while ステートメントと if/else ステートメントがあるのはなぜですか?

その表情をもう10年以上見てきた。何がいいのか考えてみました。主に #defines で見られるので、内部スコープ変数の宣言と、(goto の代わりに) ブレークの使用に適していると思います。

他にいいことある?使いますか?

4

5 に答える 5

570

#defineこれは、マルチステートメント操作に使用でき、後にセミコロンを付けても、ifステートメント内で使用できるCの唯一の構造です。例が役立つかもしれません:

#define FOO(x) foo(x); bar(x)

if (condition)
    FOO(x);
else // syntax error here
    ...;

中かっこを使用しても役に立ちません。

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

ステートメントでこれを使用ifするには、セミコロンを省略する必要があります。これは直感に反します。

if (condition)
    FOO(x)
else
    ...

このようにFOOを定義する場合:

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

その場合、構文的に正しいのは次のとおりです。

if (condition)
    FOO(x);
else
    ....
于 2008-11-02T21:40:11.380 に答える
124

これは、エラー チェックを簡素化し、深いネストされた if を回避する方法です。例えば:

do {
  // do something
  if (error) {
    break;
  }
  // do something else
  if (error) {
    break;
  }
  // etc..
} while (0);
于 2008-11-02T21:38:44.207 に答える
99

関数のようなマクロを実際に関数として使用できるように、複数のステートメントを1つのステートメントにグループ化するのに役立ちます。あなたが持っているとしましょう:

#define FOO(n)   foo(n);bar(n)

そしてあなたはする:

void foobar(int n) {
  if (n)
     FOO(n);
}

次に、これは次のように展開されます。

void foobar(int n) {
  if (n)
     foo(n);bar(n);
}

2番目の呼び出しはステートメントbar(n)の一部ではなくなっていることに注意してください。if

両方をにラップすると、ステートメントdo { } while(0)でマクロを使用することもできます。if

于 2008-11-02T21:39:51.147 に答える
20

do {} while(0)ループが機能しない次の状況に注意するのは興味深いことです。

値を返す関数のようなマクロが必要な場合は、do {} while(0)の代わりにステートメント式:({stmt; stmt;})が必要になります。


#include <stdio.h>

#define log_to_string1(str, fmt, arg...) \
    do { \
        sprintf(str, "%s: " fmt, "myprog", ##arg); \
    } while (0)

#define log_to_string2(str, fmt, arg...) \
    ({ \
        sprintf(str, "%s: " fmt, "myprog", ##arg); \
    })

int main() {
        char buf[1000];
        int n = 0;

        log_to_string1(buf, "%s\n", "No assignment, OK");

        n += log_to_string1(buf + n, "%s\n", "NOT OK: gcc: error: expected expression before 'do'");

        n += log_to_string2(buf + n, "%s\n", "This fixes it");
        n += log_to_string2(buf + n, "%s\n", "Assignment worked!");
        printf("%s", buf);
        return 0;
}
于 2011-01-07T16:34:43.857 に答える
-6

一般に、do/は、ループを少なくともwhile1 回実行する必要があるあらゆる種類のループ構造に適しています。この種のループをストレートまたはループでエミュレートすることは可能ですが、多くの場合、結果は少しエレガントではありません。このパターンの特定のアプリケーションはかなりまれですが、存在することは認めます。思い浮かぶのは、メニューベースのコンソール アプリケーションです。whilefor

do {
    char c = read_input();

    process_input(c);
} while (c != 'Q');
于 2008-11-02T21:39:02.940 に答える