重複の可能性:
C/C++ マクロに無意味な do/while ステートメントと if/else ステートメントがあるのはなぜですか?
その表情をもう10年以上見てきた。何がいいのか考えてみました。主に #defines で見られるので、内部スコープ変数の宣言と、(goto の代わりに) ブレークの使用に適していると思います。
他にいいことある?使いますか?
重複の可能性:
C/C++ マクロに無意味な do/while ステートメントと if/else ステートメントがあるのはなぜですか?
その表情をもう10年以上見てきた。何がいいのか考えてみました。主に #defines で見られるので、内部スコープ変数の宣言と、(goto の代わりに) ブレークの使用に適していると思います。
他にいいことある?使いますか?
#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
....
これは、エラー チェックを簡素化し、深いネストされた if を回避する方法です。例えば:
do {
// do something
if (error) {
break;
}
// do something else
if (error) {
break;
}
// etc..
} while (0);
関数のようなマクロを実際に関数として使用できるように、複数のステートメントを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
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;
}
一般に、do
/は、ループを少なくともwhile
1 回実行する必要があるあらゆる種類のループ構造に適しています。この種のループをストレートまたはループでエミュレートすることは可能ですが、多くの場合、結果は少しエレガントではありません。このパターンの特定のアプリケーションはかなりまれですが、存在することは認めます。思い浮かぶのは、メニューベースのコンソール アプリケーションです。while
for
do {
char c = read_input();
process_input(c);
} while (c != 'Q');