用于填充结构字段的C预处理器宏

时间:2017-06-27 08:42:29

标签: c gcc struct macros

说我有一些结构:

#define FILL(instance, field, value)    \
do {                                    \
    instance.#field = value;            \
    instance.has_#field = 1;            \
} while(0);                             \

我想编写一个像

这样的宏
struct mything1 x; FILL(x, foo, 5);

所以我可以去Send the token to another user Sharing Realm Between Users. 1.Send the token to another user via any method. 但是当我尝试编译它时这不起作用。这有可能吗?这是否可取?

GCC特定的非便携式解决方案很好。

2 个答案:

答案 0 :(得分:4)

您正在将field字符串化为"field",而不是通过其标识符引用该字段。请注意,令牌连接是使用##完成的,而不是#。一个小修复:

#define FILL(instance, field, value)    \
do {                                    \
    instance.field = value;             \
    instance.has_##field = 1;           \
} while(0)                              

我还在while(0)之后删除了分号。该习惯用于通过在使用宏完成语句后使用分号来使FILL(x, foo, 5);工作。否则,你最终会得到一个可以引发警告的尾随空语句。

答案 1 :(得分:2)

这是一个" XY问题"。没有理由使用宏,这只是简单的混淆。不要这样做。

相反,只需使用指定的初始值设定项:

struct mything1 x = 
{
  .foo = 5
};

如果你想要" has_foo"同时设置,考虑用适当的设计解决这个问题:

typedef struct
{
  int  value;
  bool exists;
} thing_t;

typedef struct
{
  thing_t foo;
  thing_t bar;
} many_things_t;

many_things_t things = 
{
  .foo = {5, true}
};

作为最后的手段,如果你真的坚持使用结构并且你真的必须有一个宏而不是一个函数,由于原因未知,那么至少使用标准约定如何写这样的宏。

在这种情况下,使用" X宏"可能是明智的,因为它们是为避免代码重复而设计的。您可以列出字段名称和初始值设定项:

#define THING_LIST \
  X(foo, 5)        \
  X(bar, 7)  

完整示例:

#include <stdio.h>

struct mything1 {
   int foo;
   int has_foo;

   int bar;
   int has_bar;
};

#define THING_LIST \
  X(foo, 5)        \
  X(bar, 7)  

int main() 
{
  struct mything1 thing = 
  {
    #define X(field, value) \
      .field = value,       \
      .has_##field = 1,
    THING_LIST
    #undef X
  };

  printf("foo: %d has_foo: %d\n", thing.foo, thing.has_foo);
  printf("bar: %d has_bar: %d\n", thing.bar, thing.has_bar);
}