[英]Expand a macro in a macro
给定以下宏以函数调用方式访问编译器属性,例如spec(section(".mysection")) void foo(void);
:
#define spec(_H_) spec_##_H_
#define spec_section(_S_) attribute ((section (_S_)))
我现在想在其他宏中使用这些定义,例如spec(namespace(unmanaged)) int x;
:
#define spec_namespace(_H_) spec_namespace_##_H_
#define spec_namespace_unmanaged spec(section(".unmanaged"))
但这根本没有扩展,使其工作的唯一方法是自己编写扩展的 spec() 宏:
#define spec_namespace_unmanaged spec_section(".unmanaged")
知道发生了什么吗? gcc -E on spec(namespace(unmanaged))
导致spec(namespace(unmanaged))
。
引用C99草案6.10.3.4
重新扫描和进一步替换 §2(强调我的):
如果在替换列表的扫描期间找到了要替换的宏的名称(不包括源文件的其余预处理令牌),则不会替换该宏。 此外,如果任何嵌套的替换遇到要替换的宏的名称, 则不会替换它。 这些未替换的宏名称预处理令牌不再可用于进一步替换,即使它们后来在本来会被替换的宏名称预处理令牌的上下文中进行了(重新)检查。
根据以下宏定义:
#define spec(_H_) spec_##_H_
#define spec_namespace(_H_) spec_namespace_##_H_
#define spec_namespace_unmanaged spec(section(".unmanaged"))
显然, spec
宏被评估了两次,因此没有进一步的替换,让我们逐步进行:
spec(namespace(unmanaged)) int x; → spec_namespace(unmanaged) int x;
spec_namespace(unmanaged) int x; → spec_namespace_unmanaged int x;
spec_namespace_unmanaged int x; → spec(section(".unmanaged")) int x;
您可以做的就是将您的最后一个宏定义修改为以下形式:
#define spec_namespace_unmanaged attribute ((namespace (".unmanaged")))
或简化为:
#define spec(_H_) spec_##_H_
#define spec_section(_S_) attribute ((section (_S_)))
#define spec_namespace(_N_) attribute ((namespace (_N_)))
有:
spec(namespace(".unmanaged")) int x;
简而言之,如果在右侧(在宏定义中)没有将字符串化运算符#
和连接运算符##
应用于它,预处理器只会在左侧(在另一个宏的参数中)扩展嵌套宏。
强制嵌套宏扩展的惯用方法是使用辅助宏:
#define macro_helper(x) macro(x) // gets x expanded
考虑以下示例,该示例扩展了嵌套的__LINE__
宏:
#include <iostream>
#define MACRO1(L) "Line " #L // MACRO1(__LINE__) -> "Line " "__LINE__")
#define MACRO2 MACRO1(__LINE__) // MACRO2 -> MACRO1(__LINE__)
#define MACRO3(L) "Line " #L // MACRO3(13) -> "Line " "13")
#define MACRO4(L) MACRO3(L) // MACRO4(__LINE__) -> MACRO3(13)
#define MACRO5 MACRO4(__LINE__) // MACRO5 -> MACRO4(__LINE__)
int main()
{
std::cout << MACRO2 << std::endl; // Output: "Line __LINE__"
std::cout << MACRO5 << std::endl; // Output: "Line 13"
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.