将宏的字符串形式(名称)与宏的字符串形式(展开后的值)进行比较:
#include <iostream>
#include <cstring>
#define TRACE_STRINGIFY(item) "" #item
#define TRACE(macro, message) \
do { \
if (strcmp("" #macro, TRACE_STRINGIFY(macro))) \
std::cout << message << "\n"; \
} while (0)
"" # 宏
将宏名展开为字符串,而
TRACE_STRINGIFY(macro)
首先展开宏,然后将结果转化为字符串。如果两者不同,则
macro
必须是一个预处理器宏。
这种方法对于定义为自身的宏(例如
#define FOO FOO
)会失败。这样的宏不会被检测为预处理器宏。
大多数编译器应该能够完全优化掉两个字符串字面值的比较。GNU GCC (g++) 4.8.2 在
-O0
下肯定可以(gcc for C 也一样 -- 这种方法在 C 语言中同样有效)。
这种方法对于函数式宏确实有效,但只有在保留括号(如果宏有多个参数,则还需要正确的逗号数)且未定义为自身时才有效(例如
#define BAR(x) BAR(x)
)。
例如:
#define TEST1 TEST1
#define TEST3
#define TEST4 0
#define TEST5 1
#define TEST6 "string"
#define TEST7 ""
#define TEST8 NULL
#define TEST9 TEST3
#define TEST10 TEST2
#define TEST11(x)
#define TEST13(x,y,z) (x, y, z)
int main(void)
{
TRACE(TEST1, "TEST1 is defined");
TRACE(TEST2, "TEST2 is defined");
TRACE(TEST3, "TEST3 is defined");
TRACE(TEST4, "TEST4 is defined");
TRACE(TEST5, "TEST5 is defined");
TRACE(TEST6, "TEST6 is defined");
TRACE(TEST7, "TEST7 is defined");
TRACE(TEST8, "TEST8 is defined");
TRACE(TEST9, "TEST9 is defined");
TRACE(TEST10, "TEST10 is defined");
TRACE(TEST11, "TEST11 is defined");
TRACE(TEST12, "TEST12 is defined");
TRACE(TEST13, "TEST13 is defined");
TRACE(TEST14, "TEST14 is defined");
TRACE(TEST1(), "TEST1() is defined");
TRACE(TEST2(), "TEST2() is defined");
TRACE(TEST3(), "TEST3() is defined");
TRACE(TEST4(), "TEST4() is defined");
TRACE(TEST5(), "TEST5() is defined");
TRACE(TEST6(), "TEST6() is defined");
TRACE(TEST7(), "TEST7() is defined");
TRACE(TEST8(), "TEST8() is defined");
TRACE(TEST9(), "TEST9() is defined");
TRACE(TEST10(), "TEST10() is defined");
TRACE(TEST11(), "TEST11() is defined");
TRACE(TEST12(), "TEST12() is defined");
TRACE(TEST13(,,), "TEST13(,,) is defined");
TRACE(TEST14(,,), "TEST14(,,) is defined");
return 0;
}
它输出
TEST3 is defined
TEST4 is defined
TEST5 is defined
TEST6 is defined
TEST7 is defined
TEST8 is defined
TEST9 is defined
TEST10 is defined
TEST3() is defined
TEST4() is defined
TEST5() is defined
TEST6() is defined
TEST7() is defined
TEST8() is defined
TEST9() is defined
TEST10() is defined
TEST11() is defined
TEST13(,,) is defined
换句话说,未将
TEST1
符号识别为已定义(因为它被定义为自身),不带括号的
TEST11
或
TEST13
也是如此。这些是这种方法的限制。
对于所有无参数宏(除了
TEST1
,即那些被定义为自身的宏)和所有单参数宏,使用括号形式都有效。如果一个宏期望多个参数,您需要使用正确数量的逗号,否则(例如,如果您尝试
TRACE(TEST13(),"...")
),您将得到一个编译时错误:
“宏TEST13
需要3个参数,但只给出了1个”或类似的信息。
还有问题吗?