c预处理器将多个参数作为一个传递

ali*_*ice 12 c macros c-preprocessor

C预处理器传递多个参数,就好像它们是单个参数一样.我非常确定问题是我们如何调用untouchable宏,但是我们为改变first宏所做的每一次尝试都未能产生预期的结果.这是一个包含注释的完整代码示例,用于解释发生了什么以及我们想要发生什么:

//this can be changed, but it must remain a #define to be of any use to us
#define first a,b,c

// v all code below this line cannot be altered (it's outside of our control)

#define untouchable(name, c1, c2, c3) \
    wchar_t name[] = \
    { \
        quote(c1), \
        quote(c2), \
        quote(c3) \
    }

#define quote(c) L#@c

// ^ all code above this line cannot be altered (it's outside of our control)

int _tmain(int argc, _TCHAR* argv[])
{
    static untouchable(mrNess, first);

    // the line above is precompiled to:
    // static wchar_t mrNess[] = { L'a,b,c', L, L };

    // whereas we want:
    // static wchar_t mrNess[] = { L'a', L'b', L'c' };

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们正在VisualStudio中的Windows中进行编译.

Rud*_*uis 5

问题似乎在于你如何定义first。你传给firstuntouchable但当时显然还没有展开

因此,不要使用first这样的宏,并将a, b, 和c作为单个参数传递给宏。然后你就会得到你想要的。

更新

但还是有一些希望:

#define UT_HELPER(a,b,c,d) untouchable(a,b,c,d)
#define UT(x, y) UT_HELPER(x, y)
#define first a, b, c
static UT(mrNess, first);
Run Code Online (Sandbox Code Playgroud)

它与此堆栈溢出答案中找到的解决方案类似,因此我不能声称是我自己想到的。

注意

#define quote(s) L#@s
Run Code Online (Sandbox Code Playgroud)

在我的编译器中不起作用,所以我无法完全测试它。我只是尝试过

#define quote(s) L###s
Run Code Online (Sandbox Code Playgroud)

这奏效了。

我希望这能让您了解真正的、更复杂的宏。


Joh*_*ger 5

当预处理器遇到类函数宏的调用时,它首先识别参数,然后完全宏扩展它们*,最后用其替换列表替换宏调用,并在适当的位置插入扩展参数.宏的扩展first(或将会)执行得太迟,以至于预处理器无法在扩展中识别宏的单独参数untouchable().你需要找到另一种方式.

一种可能性是插入一个间接级别:

#define untouch_wrap(name, args) untouchable(name, args)

static untouch_wrap(mrNess, first);
Run Code Online (Sandbox Code Playgroud)

在那里,first之前进行了扩展untouch_wrap,以便在重新扫描结果以进一步替换宏时,生成的调用untouchable()具有正确数量的参数.

这确实依赖于第二个参数来untouch_wrap()扩展为以逗号分隔的正好三个成员的列表.这样定义会更清晰,更灵活untouch_wrap():

#define untouch_wrap(name, ...) untouchable(name, __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

...但是MSVC对可变参数宏的处理是不一致的,我怀疑它会绊倒它.


*对于作为预处理程序的stringification(#)和token-pasting(##)运算符的操作数的参数,将禁止扩展.