【问题标题】:Expand a macro in a macro在宏中展开宏
【发布时间】:2014-07-28 08:30:10
【问题描述】:

鉴于以下宏以函数调用方式访问编译器属性,例如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))。

【问题讨论】:

标签: c macros c-preprocessor


【解决方案1】:

引用 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;

【讨论】:

    【解决方案2】:

    简单地说,如果字符串化操作符#和连接操作符##都没有应用到它的右侧(在宏定义中)。

    idiomatic way 强制嵌套宏扩展是使用辅助宏:

    #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"
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-20
      • 1970-01-01
      • 1970-01-01
      • 2018-10-14
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      相关资源
      最近更新 更多