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

时间:2016-07-12 19:45:56

标签: 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;
}

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

3 个答案:

答案 0 :(得分:5)

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

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

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

static untouch_wrap(mrNess, first);

在那里,firstuntouch_wrap之前展开,因此当重新扫描结果以进一步替换宏时,untouchable()的结果调用具有正确数量的参数。

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

#define untouch_wrap(name, ...) untouchable(name, __VA_ARGS__)

...但是MSVC对可变参数宏的处理是不符合的,我怀疑它会超过它。

* 对于作为预处理器的字符串化(#)和令牌粘贴(##)运算符的操作数的参数,扩展被抑制。

答案 1 :(得分:4)

问题似乎是你如何定义first。您将first传递给untouchable,但显然当时没有展开

所以不要像这样使用first宏,并将abc作为宏的单个参数传递。然后你会得到你想要的东西。

更新

但是有一些希望:

#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);

它类似于this stack overflow answer中找到的解决方案,所以我不能声称自己已经考虑过了。

请注意

#define quote(s) L#@s

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

#define quote(s) L###s

这很有效。

我希望这能帮助你找到你真正的,更复杂的宏。

答案 2 :(得分:1)

C11,6.10.3.1参数替换:

  

调用类似函数的宏的参数之后   已经确定,参数替换发生。一个参数   替换列表,除非前面有#或##预处理令牌或   后跟##预处理令牌(见下文),替换为   在其中包含的所有宏之后的相应参数   扩大。在被替换之前,每个参数的预处理   令牌完全被宏观取代,好像它们形成了其余部分   预处理文件;没有其他预处理令牌可供使用。

看看它是如何扩展的:

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

untouchable(foo,first,c,d)

成:

$ gcc -E foo.c
...

wchar_t foo[] = { quote(a,b,c), quote(c), quote(d) }  

首先识别参数,因此不可触摸的参数首先变为c1。只有在识别它们之后,它们才会被扩展,然后被替换为宏体。 first -> c1 -> a,b,c。现在在宏体中,c1被a,b,c替换。

我从问题中跳过了引用宏,因为它在我的编译器上是非法的。