使用 ## 和 __LINE__ 创建 C 宏(与定位宏的标记连接)
Posted
技术标签:
【中文标题】使用 ## 和 __LINE__ 创建 C 宏(与定位宏的标记连接)【英文标题】:Creating C macro with ## and __LINE__ (token concatenation with positioning macro) 【发布时间】:2010-12-08 11:52:24 【问题描述】:我想创建一个 C 宏来创建一个基于名称的函数 行号上。 我想我可以做类似的事情(真正的函数会在大括号内声明):
#define UNIQUE static void Unique_##__LINE__(void)
我希望可以扩展为:
static void Unique_23(void)
这行不通。使用令牌连接,定位宏 被逐字处理,最终扩展为:
static void Unique___LINE__(void)
这样可以吗?
【问题讨论】:
我认为您可以使用 indirect macro expansion。 How to concatenate twice with the C preprocessor and expand a macro as in "arg ## _ ## MACRO"? 的可能副本 除了__LINE__
之外的任何宏都是如此(尽管这是一个常见的用例。
【参考方案1】:
问题是当你有一个宏替换时,如果字符串化操作符#
和标记粘贴操作符##
都没有应用到它,预处理器只会递归地扩展宏。因此,您必须使用一些额外的间接层,您可以使用带有递归扩展参数的标记粘贴运算符:
#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void)
然后,__LINE__
在UNIQUE
的扩展过程中被扩展为行号(因为它不涉及#
或##
),然后令牌粘贴发生在TOKENPASTE
的扩展过程中.
还应注意,还有__COUNTER__
宏,它在每次求值时扩展为一个新整数,以防您需要在同一行上有多个UNIQUE
宏的实例化。注意:__COUNTER__
受 MS Visual Studio、GCC(自 V4.3 起)和 Clang 支持,但不是标准 C。
【讨论】:
恐怕这不适用于 GNU cpp。 TOKENPASTE 使用 LINE 作为文字。 TOKENPASTE(Unique_, LINE) 扩展为 Unique___LINE__ @DD:哦,现在修复了。它需要 2 层间接,而不是 1 层。__COUNTER__
宏在 gcc 中对我不起作用;尽管__LINE__
确实像宣传的那样工作。
对于尝试 COUNTER 的任何人的一些额外信息,根据msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx,这是一个特定于 Microsoft 的宏。
任何解释为什么你需要2级间接?我只尝试了一个,没有#和##,并且没有在VS2017上扩展它。显然,GCC 也是如此。但是,如果您添加第二级间接,那么它确实会扩展。魔法?【参考方案2】:
GCC 不需要“包装”(或实现),除非结果需要“字符串化”。 Gcc 有一些功能,但所有功能都可以使用纯 C 版本 1 完成(有些人认为 Berkeley 4.3 C 速度快得多,值得学习如何使用)。
**Clang (llvm) 没有正确地为宏扩展做空白 - 它添加了空白(这肯定会破坏结果作为进一步预处理的 C 标识符)**,clang 根本不做 # 或* 作为 C 预处理器的宏扩展预计将持续数十年。主要的例子是编译 X11,宏“Concat3”被破坏,它的结果现在是 MISNAMED C Identifier,当然无法构建。我开始认为构建失败是他们的职业。
我认为这里的答案是“打破标准的新 C 是糟糕的 C”,这些黑客总是选择(破坏命名空间)他们无缘无故地更改默认值,但并没有真正“改进 C”(除非他们自己这么说:我说这是一个装置,用来解释为什么他们逃脱了没有人让他们负责的所有破损)。
早期的 C 预处理器不支持 UNIq_()__ 这不是问题,因为它们支持 #pragma,它允许“将代码中的编译器品牌hackery 标记为hackery”并且还可以运行在不影响标准的情况下也一样:就像更改默认值是无用的馄饨破坏一样,就像在使用相同名称(命名空间破坏)时更改函数的功能一样......在我看来是恶意软件
【讨论】:
以上是关于使用 ## 和 __LINE__ 创建 C 宏(与定位宏的标记连接)的主要内容,如果未能解决你的问题,请参考以下文章
C语言预定义宏 __func____FUNCTION____LINE____FILE____DATE____TIME__
C语言预定义宏 __func____FUNCTION____LINE____FILE____DATE____TIME__
C/C++中的__FILE____LINE__#line__func__关键字(预定义宏)