使用##和__LINE__创建C宏(与定位宏连接的令牌)
我想创建一个C宏,根据行号创建一个名字的函数。 我以为我可以做一些事情(真正的功能将有大括号内的声明):
#define UNIQUE static void Unique_##__LINE__(void) {}
我希望能扩展到如下的东西:
static void Unique_23(void) {}
这是行不通的。 通过令牌连接,定位宏被字面处理,最终扩展为:
static void Unique___LINE__(void) {}
这可能吗?
(是的,有一个真正的原因,我想要做到这一点,不管这看起来多么无用)。
问题是,当你有一个宏的替换,预处理器将只扩大宏的递归,如果没有字符串操作符#
和令牌粘贴操作符##
应用到它。 所以,你必须使用一些额外的间接层,你可以用递归扩展的参数来使用token-pasting操作符:
#define TOKENPASTE(x, y) x ## y #define TOKENPASTE2(x, y) TOKENPASTE(x, y) #define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}
然后,在扩展UNIQUE
期间__LINE__
被扩展为行号(因为它不涉及#
或##
),然后在TOKENPASTE
扩展期间发生令牌粘贴。
还应该注意的是,还有一个__COUNTER__
宏,它在每次求值时展开为一个新的整数,以防需要在同一行上有多个UNIQUE
宏的实例。 注意: __COUNTER__
被MS Visual Studio,GCC(自V4.3)和Clang支持,但不是标准C.
GCC不需要“包装”(或实现),除非结果需要“串化”。 海湾合作委员会有功能,但所有可以用简单的C版本1(和一些认为伯克利4.3 C是如此之快,值得学习如何使用)。
** Clang(llvm)对于宏扩展不能正确地使用白色空格 – 它增加了空格(这肯定会将结果作为C标识符进行进一步的预处理)**,clang根本不会执行#或* macro expansion作为C预处理器预计将持续数十年。 主要的例子是编译X11,宏“Concat3”被破坏,结果是现在是MISNAMED C标识符,这当然不能建立。 我开始建造失败是他们的职业。
我认为这里的答案是“打破标准的新C是坏的C”,这些黑客总是选择(clobber命名空间),他们无缘无故地改变默认值,但并不真正“提高C”(除了他们自己的说法:说是为了解释为什么他们摆脱了所有的破坏,没有人让他们负责)。
之前的C预处理器不支持UNIq _()__,因为它们支持#pragma,它允许“编译器品牌hackery在代码中被标记为hackery”,而且在不影响标准的情况下也是如此:默认是无用的馄饨破损,就像使用相同的名称(名称空间破坏)改变一个函数的功能是…在我看来,恶意软件