4

ここでは次のように簡略化されたデバッグ機能があるとします。

void DumpString(char* var, char* varname) {
    printf("%s : '%s'\n", varname, var);
}

char str[10]="foobar";
DumpString(str, "str");

> str : foobar

変数を 2 回 (1 回は引用符で囲んで) 渡すという不必要な余分な要件を削除して、簡単にしましょう。

#define VARASSTR(v) #v

void DumpString(char* var) {
    printf("%s : '%s'\n", VARASSTR(var), var);
}

char str[10]="foobar";
DumpString(str);

> var : foobar

おっとっと!渡されたものではなく、ローカル変数名を使用します。別の (あまり理想的ではない) 方法を試してみましょう。

#define DumpStr(v) DumpString(v, #v)

void DumpString(char* var, char* varname) {
    printf("%s : '%s'\n", varname, var);
}

char str[10]="foobar";
DumpStr(str);

> str : foobar

それはうまくいきます。しかし、関数がもう少し複雑だったらどうでしょう。

void DumpString(char* var, char* varname, int optionalvar=0) {
    printf("%s : '%s'\n", varname, var);
    printf("blah: %d", optionalvar);
}

マクロをオーバーロードすることはできないため、DumpStr機能しませんVARASSTR。.

これをどのように処理できますか (複数の似たような名前の関数/マクロに頼ることなく)。

4

1 に答える 1

1

これは非標準ですが、GNU C の拡張機能として機能します。

#define DumpStr(v, ...) DumpString(v, #v, ##__VA_ARGS__)

##GNU C では、可変引数マクロに引数を渡すことができず、コンマと空の可変引数リストの間に適用された"トークン貼り付け演算子"は何も生成しません (したがって、末尾のコンマは抑制されます)。

##Visual C++ では、空の可変引数リストの前に末尾のコンマが表示されると、Visual C++ は自動的に末尾のコンマを抑制するため、トークンの貼り付け演算子は不要です (おそらくマクロが壊れるでしょう)。

これを非標準にする唯一の理由は、空の引数リストを時々渡したいという欲求であることに注意してください。Variadic マクロは、C99 と C++11 の両方で標準化されています。


編集:非標準機能を使用しない例を次に示します。一部の人々が、この種のことが標準で対処されることを本当に、本当に望んでいる理由がわかります。

#define DUMPSTR_1(v) DumpString(v, #v)
#define DUMPSTR_2(v, opt) DumpString(v, #v, opt)
#define DUMPSTR_NARG(...) DUMPSTR_ARG_N(__VA_ARGS__, 4, 3, 2, 1, 0)
#define DUMPSTR_ARG_N(_1, _2, _3, _4, n, ...) n
#define DUMPSTR_NC(f, ...) f(__VA_ARGS__)
#define DUMPSTR_NB(nargs, ...) DUMPSTR_NC(DUMPSTR_ ## nargs, __VA_ARGS__)
#define DUMPSTR_NA(nargs, ...) DUMPSTR_NB(nargs, __VA_ARGS__)
#define DumpStr(...) DUMPSTR_NA(DUMPSTR_NARG(__VA_ARGS__), __VA_ARGS__)

これを行うには、おそらくいくつかのよりクリーンな方法があります。しかし、それほど多くはありません。


編集 2: Rの厚意により、非標準機能を使用しない別の例を次に示し ます。

#define STRINGIFY_IMPL(s) #s
#define STRINGIFY(s) STRINGIFY_IMPL(s)
#define ARG1_IMPL(a, ...) a
#define ARG1(...) ARG1_IMPL(__VA_ARGS__, 0)
#define DumpStr(...) DumpString(STRINGIFY(ARG1(__VA_ARGS__)), __VA_ARGS__)

DumpStringこれには、文字列化された関数名が最初の引数になるように、引数の順序を変更する必要があることに注意してください。

于 2012-04-02T00:18:32.907 に答える