更简单定义多行C宏的任何技巧?

时间:2017-04-11 10:54:04

标签: c macros c-preprocessor generic-programming

我正在尝试使用宏在C中编写一些可重用的通用类型安全代码,类似于klib的工作方式:

#define Fifo_define(TYPE) \
   \
   typedef struct { \
       TYPE *head; \
       TYPE *tail; \
       size_t capacity; \
   } Fifo_##TYPE, *pFifo_##TYPE; \
   \
   inline Fifo_##TYPE * Fifo_##TYPE##_init(size_t capacity) { \
       Fifo_##TYPE * fifo = calloc(1, sizeof(Fifo_##TYPE)); \
       TYPE * data = calloc(capacity, sizeof(TYPE)); \
       fifo->head = data; \
       fifo->tail = data; \
       fifo->capacity = capacity; \
   }

// define macros       

#define Fifo(TYPE) Fifo_##TYPE
#define Fifo_init(TYPE, capacity) Fifo_##TYPE_init(capacity)

然后我只使用任何类型参数:

Fifo_define(int32_t);
...
Fifo(int32_t) *myFifo = Fifo_init(int32_t, 100);

然而,写这个是相当复杂且容易出错的,没有IDE编辑器支持(IntelliSense),所以我想知道是否有任何技巧可能允许我(可能)添加一些定义然后包含文件,必须以\结束每一行?

类似的东西:

// no idea how to do this, just checking if similar concept is possible

#define FIFO_TYPE int
#define FIFO_NAME Fifo_int

#include <generic-fifo.h>

#undef FIFO_NAME
#undef FIFO_TYPE

我会以某种方式获得所有正确的struct和功能。问题是这些宏中有很多参数连接,所以我不确定这是否可以比第一个片段更简单的方式完成?

2 个答案:

答案 0 :(得分:1)

在这种情况下并不是真的推荐,但是您可以使用X-macros执行类似的操作:

#define SUPPORTED_TYPES \
  X(int)                \
  X(double)             \
  X(char)

#define X(TYPE)         \
   typedef struct {     \
       TYPE *head;      \
       TYPE *tail;      \
       size_t capacity; \
   } Fifo_##TYPE, *pFifo_##TYPE;
SUPPORTED_TYPES
#undef X

#define X(TYPE)                                          \
inline Fifo_##TYPE * Fifo_##TYPE##_init(size_t capacity) \
{                                                        \
  Fifo_##TYPE * fifo = calloc(1, sizeof(Fifo_##TYPE));   \
  TYPE * data = calloc(capacity, sizeof(TYPE));          \
  fifo->head = data;                                     \
  fifo->tail = data;                                     \
  fifo->capacity = capacity;                             \
}
SUPPORTED_TYPES
#undef X

但这并没有真正改善这种情况。它摆脱了对单个丑陋的Fifo_define宏的需求,因此您可以将代码分成几个部分。但宏观问题仍然存在。

我会推荐一些完全不同的方法。两个建议:

  • 在运行时以经典C方式处理类型泛型。使用回调。如果需要,使用枚举跟踪使用的类型。

  • C11 _Generic允许各种类型的安全技巧,可以用来淘汰这些凌乱的宏。 Example that implements "functors"。宏本身保持最小,并且键入了各种类型的不同实现。 (这通常是你最后做的事情,当你进行类型通用编程时。)

答案 1 :(得分:1)

如果您使用的是复杂的宏,请考虑使用m4而不是C预处理器。 m4 is similar to the C pre-processor but is much more powerful并且可以执行多行没有行继续符的事情。

使用像m4这样的代码生成器称为 meta-programming

在C中使用m4可以通过将其视为预处理前like this来实现:

% grep -v '#include' file1 file2 | m4 > outfile
% m4 file1 file2 | cc

由于m4的工作方式与基本级别的C预处理器类似,因此除了支持自己的高级功能外,它通常还可以正确转换任何普通的C宏。