C预处理器宏扩展限制,使用带有参数的imbricated宏

时间:2018-02-07 17:53:26

标签: c macros

我已经制作了一些宏来帮助我在gcc项目中设计一个对话框的小部件。 但是我收到了编译错误,所以我做了以下测试:

#define XPOS_ISAFTER(obj) (obj##_XPOS + obj##_XSIZE)

#define PMD_TUTU_XPOS 10
#define PMD_TUTU_XSIZE 10

#define PMD_TUTU2_XPOS  XPOS_ISAFTER(PMD_TUTU)
#define PMD_TUTU2_XSIZE 20

#define PMD_TUTU3_XPOS  XPOS_ISAFTER(PMD_TUTU2)


int main(void){
int i = 0;
    printf("Hello World!\n");
    fflush(stdout);

      /* Infinite loop */
      while (1)
      {
          i += PMD_TUTU2_XPOS;
          i += PMD_TUTU3_XPOS;
      }

    return 0;
}

当要求预处理器输出时,我得到以下内容:

839 int main(void){
840     int i = 0;
841         printf("Hello World!\n");
842             fflush(stdout);
843
844
845                   while (1)
846                           {
847                                       i += (10 + 10);
848                                       i += (XPOS_ISAFTER(PMD_TUTU) + 20);
849                                                   }
850
851                     return 0;

我搜索了一些建议tricks以强制重新扫描,但没有任何结果。 那么预处理器不会扩展这个递归宏吗?

2 个答案:

答案 0 :(得分:1)

问题不在于预处理器无法重新扫描,而是在它执行时,它拒绝扩展文本中XPOS_IS_AFTER()宏的外观,从而导致(间接)从同一宏的先前扩展。换句话说,预处理器不支持宏递归。这由标准明确规定:

  

[重新扫描宏的替换文本时],如果在替换列表的扫描期间找到要替换的宏的名称(不包括源文件的其余预处理标记),它没有被替换。此外,如果任何嵌套替换遇到要替换的宏的名称,则不会替换它。这些未替换的宏名称预处理令牌不再可用于进一步替换,即使它们稍后(重新)检查其中宏名称预处理令牌将被替换的上下文中。

C2011, 6.10.3.4/2

GCC完全按照您的代码执行操作。你需要一个不同的计划。

答案 1 :(得分:0)

在阅读了Paul F的预处理器技巧之后,经过多次尝试,我得出结论认为它不适用于我的情况,因为我没有明确地编写一个递归宏,因为它似乎是在变通方法中的情况我读了。

所以我写了一些效率低的宏来避免递归:

#define XPOS_ISAFTER(obj) ( obj##_XPOS + obj##_XSIZE )
#define XPOS_ISAFTER2(obj1,obj2) (XPOS_ISAFTER(obj1) + obj2##_XSIZE)
#define XPOS_ISAFTER3(obj1,obj2, obj3) (XPOS_ISAFTER2(obj1, obj2) + obj3##_XSIZE)


#define YPOS_ISUNDER(obj) ( obj##_YPOS +  obj##_YSIZE )
#define YPOS_ISUNDER2(obj1,obj2) ( YPOS_ISUNDER(obj1) + obj2##_YSIZE )
#define YPOS_ISUNDER3(obj1, obj2, obj3) ( YPOS_ISUNDER2(obj1,obj2) + obj3##_YSIZE )
#define YPOS_ISUNDER4(obj1,obj2, obj3, obj4) ( YPOS_ISUNDER3(obj1,obj2, obj3) + obj4##_YSIZE )