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中进行编译。
当预处理器遇到类函数宏的调用时,它首先识别参数,然后完全宏扩展它们*,最后用替换列表替换宏调用,并在适当的位置插入扩展参数。宏观的扩张 first
是(或将会)执行得太迟,以便预处理器在扩展中识别宏的单独参数 untouchable()
。你需要找到另一种方式。
一种可能性是插入一个间接级别:
#define untouch_wrap(name, args) untouchable(name, args)
static untouch_wrap(mrNess, first);
那里, first
以前扩大了 untouch_wrap
,以便在重新扫描结果时进一步替换宏,从而产生调用 untouchable()
具有正确数量的参数。
这确实依赖于第二个论点 untouch_wrap()
扩展到以逗号分隔的正好三个成员的列表。定义更清晰,更灵活 untouch_wrap()
喜欢这个:
#define untouch_wrap(name, ...) untouchable(name, __VA_ARGS__)
...但是MSVC对可变参数宏的处理是不一致的,我怀疑它会超过它。
* 对于作为预处理程序字符串化操作数的参数,扩展被抑制(#
)和令牌粘贴(##
)运营商。
问题似乎是你如何定义 first
。你过关了 first
到了 untouchable
宏, 但那时显然没有扩大。
所以不要使用 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);
它类似于在中找到的解决方案 这个堆栈溢出的答案所以我不能声称自己已经考虑过了。
注意
#define quote(s) L#@s
在我的编译器中不起作用,所以我无法完全测试它。我只是试着用
#define quote(s) L###s
那很有效。
我希望这能让你选择真正的,更复杂的宏。
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
。
我从问题中跳过了引用宏,因为它在我的编译器上是非法的。