これは、次の 2 つの注意事項で実行できます。
- コンパイラは可変長マクロをサポートする必要があります (C99 標準の一部でした)。
0,
マクロ トークンを定義するときに追加する必要があります。つまり、
#define MACRO 0, HelloWorld
上記を考えると、RESOLVE
私が思いついたこの気の利いたマクロを使用できます。これは1行のバージョンです(より防弾/移植可能にすることができます):
#define RESOLVE(token, default_token, ...) default_token
ここでは、サンプル コードに適用されます。
#include <stdio.h>
#define BLANK
#define RESOLVE(token, default_token, ...) default_token
#define QUOTE(str) #str
#define QUOTE0(str) QUOTE(str) // need the intermediate QUOTE0 function here or else you get output like `RESOLVE(0, HelloWorld, , )` instead of `HelloWorld`
#define EXPAND_AND_QUOTE(str, ...) QUOTE0(RESOLVE(str, BLANK, __VA_ARGS__)) // the BLANK token is optional here, can also be a literal blank
#define MACRO 0, HelloWorld
int main() {
printf("%s\n", EXPAND_AND_QUOTE(MACRO));
printf("%s\n", QUOTE(MACRO));
#undef MACRO
printf("%s\n", EXPAND_AND_QUOTE(MACRO));
printf("%s\n", QUOTE(MACRO));
}
コンパイルしてテストすると、出力は確かに
HelloWorld
MACRO
MACRO
仕組みRESOLVE
_
基本的な考え方は、プリプロセッサは定義されたトークンと未定義のトークンを区別できませんが (未定義のトークンと通常のテキストを区別しないため)、少なくとも関数のようなマクロのパラメーター リスト内では、単一のトークンとタプルを区別できます。 . __VA_ARGS__
次に、マクロがこの区別に基づいて異なる動作を生成できるようにします。
2 つの定義済みトークンがあるとします。
#define BAR bar
#define BAZ baz0, baz1
および未定義の token FOO
。これらを に渡すとRESOLVE
、効果的に展開されます
RESOLVE(FOO, BLANK) -> RESOLVE(token=, default_token=BLANK, __VA_ARGS__=) -> BLANK
RESOLVE(BAR, BLANK) -> RESOLVE(token=bar, default_token=BLANK, __VA_ARGS__=) -> BLANK
RESOLVE(BAZ, BLANK) -> RESOLVE(token=baz0, default_token=baz1, __VA_ARGS__=BLANK) -> baz1
の場合、 はBAZ
、BLANK
に格納されている 2 番目の値によって名前付きパラメータ リストの末尾から (省略記号の中に) 押し出されBAZ
、それが返されます。