【问题标题】:Why is this nested macro replacement failing?为什么这个嵌套宏替换失败?
【发布时间】:2017-09-08 11:05:12
【问题描述】:

我正在尝试应用X Macro 概念,以便有可能将所有结构成员初始化为自定义默认(无效)值。我写了以下代码:

#define LIST_OF_STRUCT_MEMBERS_foo \
    X(a) \
    X(b) \
    X(c)

#define X(name) int name;
struct foo {
     LIST_OF_STRUCT_MEMBERS_foo
};
#undef X


#define X(name) -1,
static inline void foo_invalidate(struct foo* in) {
     *in = (struct foo){
     LIST_OF_STRUCT_MEMBERS_foo
     };
}
#undef X

#define X(name) -1,
#define foo_DEFAULT_VALUE  { LIST_OF_STRUCT_MEMBERS_foo }
#undef X

static struct foo test = foo_DEFAULT_VALUE;

但是,当我运行预处理器时,foo_DEFAULT_VALUE 的定义无法将 X(name) 调用替换为 -1,

预处理器输出:

struct foo {
     int a; int b; int c;
};

static inline void foo_invalidate(struct foo* in) {
     *in = (struct foo){
     -1, -1, -1, /*Here the substitution worked nicely*/
     };
}

static struct foo test = { X(a) X(b) X(c) }; /*Why this substitution failed?*/

我以为C-macros could refer to other macros。你知道为什么替换失败吗?有什么解决办法吗?

我可以接受foo_invalidate,但我不愿意放弃在初始化时直接使用值的一步。

【问题讨论】:

  • 您将X(name) 定义为-1, 周围的#definefoo_DEFAULT_VALUE,但不是您实际使用它的位置。您需要在 static struct foo test = foo_DEFAULT_VALUE; 行周围定义发生替换的 X 宏。

标签: c macros initialization c-preprocessor


【解决方案1】:

让我们假设我们是预处理器并遇到以下行:

static struct foo test = foo_DEFAULT_VALUE;

通过 1:

static struct foo test = { LIST_OF_STRUCT_MEMBERS_foo };

通过 2:

static struct foo test = { X(a) X(b) X(c) };

通过 3:没有可扩展的内容,因为 X 在此行上未定义。


一种解决方法是定义一个 const 变量(可能但不一定是 static)作为默认值:

#define X(name) -1,
static const struct foo foo_DEFAULT_VALUE = { LIST_OF_STRUCT_MEMBERS_foo };
#undef X

生成:

static const struct foo foo_DEFAULT_VALUE = { -1, -1, -1, };

【讨论】:

  • 有什么解决方法?我考虑过以下问题,但我想知道它是否是最佳的:#define X(name) -1, #define foo_DEFAULT_VALUE_GENERATOR { LIST_OF_STRUCT_MEMBERS_foo } static const struct foo_DEFAULT_VALUE = foo_DEFAULT_VALUE_GENERATOR; #undef X
  • 嗯,直接的方式显然是这样。将 #undef 移到声明所在的行之后。否则需要重新设计。
  • 您可以将const struct foo声明为const struct foo,而不是将foo_DEFAULT_VALUE定义为扩展为初始化程序的宏。
  • 是的,@Antonio,尽管就我个人而言,我也不会为 foo_DEFAULT_VALUE_GENERATOR 宏而烦恼,因为您以后将无法使用它。我只是将其替换文本直接放入foo_DEFAULT_VALUE 的声明中。
【解决方案2】:

您可能喜欢 X_Macros 的 undef-free 版本,
它减少了在每次使用时定义和取消定义的必要注意
并且更适合在头文件中定义和在多个代码文件中使用:

#define LIST_OF_STRUCT_MEMBERS_foo(mode) \  
    X_##mode(a) \  
    X_##mode(b) \  
    X_##mode(c)  

#define X_struct(name) int name;  
#define X_list(name) -1,  
#define foo_DEFAULT_VALUE  { LIST_OF_STRUCT_MEMBERS_foo(list) }  

struct foo {  
     LIST_OF_STRUCT_MEMBERS_foo(struct)  
};  

static inline void foo_invalidate(struct foo* in) {  
     *in = (struct foo){  
     LIST_OF_STRUCT_MEMBERS_foo(list)  
     };  
}  

static struct foo test = foo_DEFAULT_VALUE;  

输出(gcc -E):

struct foo {
     int a; int b; int c;
};

static inline void foo_invalidate(struct foo* in) {
     *in = (struct foo){
     -1, -1, -1,
     };
}

static struct foo test = { -1, -1, -1, };

【讨论】:

  • 如果我说我发明了它,你会相信我吗?我并不是说我首先发明了它(可能还有其他人,更早),但我确实自己想出了它。
  • 我相信你,我昨天搜索了很多主题,从来没有遇到过这样的实现!我会尽快奖励你!
  • 大家好,如果您知道此方法的其他来源,请告诉我。如果没有人发现任何我可以声称实际上是首先发明它的东西。 ;-)
【解决方案3】:

您也可以尝试检查扩展宏的输出。如果您使用 gcc 作为编译器,gcc -E <filename> >> full_src.txt' 会有所帮助。更多详情在这里:Seeing expanded C macros

【讨论】:

  • 这正是我为填写问题的Preprocessor output: 部分所做的工作
猜你喜欢
  • 1970-01-01
  • 2015-11-15
  • 2021-08-11
  • 2014-11-09
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多