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

Any trick for simpler definition of multiline C macros?

我正在尝试使用宏在 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

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

在这种情况下不推荐,但您可以使用 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 允许各种类型安全技巧,可用于逐步淘汰此类混乱的宏。 。宏本身保持最小,并且键入了各种类型的不同实现。 (当你进行泛型编程时,这通常就是你最终要做的事情。)

如果您使用复杂的宏,请考虑使用 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 宏。