我有一个宏SOME_MACRO
。需要一个参数。
SOME_MACRO
的定义:
#define SOME_MACRO(arg) __SOME_MACRO(arg)
如果__SOME_MACRO(arg)
是"ABC"
,我希望arg
扩展到0
。如果arg
不为零,则__SOME_MACRO(arg)
应扩展为"DEF"
假设我使用参数0进行调用,即:SOME_MACRO(0)
我需要在预处理时测试参数是否为零。
#if <argument is zero> // line 1
#define __SOME_MACRO(arg) "ABC"
#elif
#define __SOME_MACRO(arg) "DEF"
#endif
我的问题是:第一行应该是什么?
举个例子:
SOME_MACRO(2)
应该扩展为"DEF"
SOME_MACRO(0)
应该扩展为"ABC"
答案 0 :(得分:2)
这是不可能的。给#if
的表达式在遇到#if
的那一行仅计算一次。每次调用宏时都无法再次对其进行评估。
正如Eric Postpischil所说,C没有任何通用的方法来使宏扩展取决于其参数。
一些可能的选择:
使用三元?:
运算符的表达式,如注释中建议的pmg所示:
#define __SOME_MACRO(arg) ((arg) ? "DEF" : "ABC")
然后SOME_MACRO(0)
将扩展为((0) ? "DEF" : "ABC")
。任何合理的编译器都会注意到该条件是一个常量,并像仅编写"ABC"
一样对其进行编译;它不应该为测试或不可达分支生成代码。只要条件本身是编译时常量,甚至可以在必须是编译时常量的表达式中使用带有三元运算符的条件。例如__SOME_MACRO(0)
可用于初始化全局变量或静态变量。
当然,如果所需的扩展不是语法上的表达式,例如如果您尝试使用宏来创建声明或定义,或者在语法上进行更详细的说明。
如果您知道将只使用一小部分可能的参数,则可以使用token pasting with the ##
operator将宏扩展为另一组宏:
#define __SOME_MACRO_0 "ABC"
#define __SOME_MACRO_1 "DEF"
#define __SOME_MACRO_2 "DEF"
#define __SOME_MACRO(arg) __SOME_MACRO_ ## arg
然后,__SOME_MACRO(0)
扩展为"ABC"
,__SOME_MACRO(2)
扩展为"DEF"
。但是,除非您编写相应的__SOME_MACRO(3)
宏,否则__SOME_MACRO_3
将不会编译,并且__SOME_MACRO(0+1)
根本无法工作,至少不会以我所知的任何方式工作。
(按照书面规定,__SOME_MACRO(0+1)
会扩展为"ABC"+1
,与"BC"
等效,在找出问题所在之前,可能会引起很多困惑。{{1} }甚至更糟...)
此外,__SOME_MACRO(1-1)
后跟#define ZERO 0
仍然无法正常工作,以为可以通过执行此操作来解决
__SOME_MACRO(ZERO)
答案 1 :(得分:1)
这是请求的行为的解决方案。不要使用它,这是一种不好的做法,您不应该尝试这样做。
/* Define __SOME_MACRO:
Defer is used so that its arguments will be macro-replaced before
Kludge is processed.
"Kludge" is pasted to arg. If this makes "Kludge0", it will be
replaced by two arguments (an empty argument, a comma, and the argument
"abc"). Otherwise, if it forms a single token, that is one argument.
(If the pasting does not form a proper token, the behavior is
undefined. Most likely, the compiler will report an error.)
The resulting argument(s) are then passed to Kludge, followed by "DEF".
Kludge is replaced by its second argument. If __SOME_MACRO's argument
was "0", this second argument is "ABC". Otherwise, it is "DEF".
*/
#define Kludge0 , "ABC"
#define Kludge(x, y,...) y
#define Defer(x, ...) Kludge(x, __VA_ARGS__)
#define __SOME_MACRO(arg) Defer(Kludge##arg, "DEF",)
__SOME_MACRO(0)
__SOME_MACRO(2)