如果 USER 被定义为带引号的字符串,则不能这样做。
但是如果 USER 只是 JACK 或 QUEEN 或 Joker 或其他任何人,您可以这样做。
有两个技巧可以使用:
- 标记拼接,您只需将标识符与另一个标识符连接起来即可。这使您无需
#define JACK 就可以与 JACK 进行比较
- 可变参数宏扩展,它允许您处理具有可变数量参数的宏。这允许您将特定标识符扩展为不同数量的逗号,这将成为您的字符串比较。
让我们开始吧:
#define JACK_QUEEN_OTHER(u) EXPANSION1(ReSeRvEd_, u, 1, 2, 3)
现在,如果我写 JACK_QUEEN_OTHER(USER),并且 USER 是 JACK,那么预处理器
把它变成EXPANSION1(ReSeRvEd_, JACK, 1, 2, 3)
第二步是串联:
#define EXPANSION1(a, b, c, d, e) EXPANSION2(a##b, c, d, e)
现在JACK_QUEEN_OTHER(USER) 变为EXPANSION2(ReSeRvEd_JACK, 1, 2, 3)
这提供了根据字符串是否匹配添加多个逗号的机会:
#define ReSeRvEd_JACK x,x,x
#define ReSeRvEd_QUEEN x,x
如果 USER 是 JACK,JACK_QUEEN_OTHER(USER) 变为 EXPANSION2(x,x,x, 1, 2, 3)
如果 USER 是 QUEEN,JACK_QUEEN_OTHER(USER) 变为 EXPANSION2(x,x, 1, 2, 3)
如果 USER 是其他,JACK_QUEEN_OTHER(USER) 变为 EXPANSION2(ReSeRvEd_other, 1, 2, 3)
此时,关键的事情发生了:EXPANSION2 宏的第四个参数是 1、2 或 3,这取决于传递的原始参数是 jack、queen 还是其他任何东西。所以我们要做的就是把它挑出来。由于冗长的原因,最后一步我们需要两个宏;它们将是 EXPANSION2 和 EXPANSION3,尽管看起来没有必要。
总而言之,我们有这 6 个宏:
#define JACK_QUEEN_OTHER(u) EXPANSION1(ReSeRvEd_, u, 1, 2, 3)
#define EXPANSION1(a, b, c, d, e) EXPANSION2(a##b, c, d, e)
#define EXPANSION2(a, b, c, d, ...) EXPANSION3(a, b, c, d)
#define EXPANSION3(a, b, c, d, ...) d
#define ReSeRvEd_JACK x,x,x
#define ReSeRvEd_QUEEN x,x
你可以这样使用它们:
int main() {
#if JACK_QUEEN_OTHER(USER) == 1
printf("Hello, Jack!\n");
#endif
#if JACK_QUEEN_OTHER(USER) == 2
printf("Hello, Queen!\n");
#endif
#if JACK_QUEEN_OTHER(USER) == 3
printf("Hello, who are you?\n");
#endif
}
必选神螺栓链接:https://godbolt.org/z/8WGa19
MSVC 更新:您必须稍微不同的括号才能使事情在 MSVC 中也能正常工作。 EXPANSION* 宏如下所示:
#define EXPANSION1(a, b, c, d, e) EXPANSION2((a##b, c, d, e))
#define EXPANSION2(x) EXPANSION3 x
#define EXPANSION3(a, b, c, d, ...) d
必填:https://godbolt.org/z/96Y8a1