可能性のある複製:
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);
関数のようなマクロを実際に関数として使用できるように、複数のステートメントを単一のステートメントにグループ化するのに役立ちます。あなたが持っていると仮定します
#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)の代わりに statement expression :({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;
}