Any trick for defining multi-line C macros more easily?

I'm trying to write some reusable universal safe code in C using macros similar to klib works:

#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)

      

And then I just use it with any type parameter:

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

      

However, writing this is quite complex and error prone with no IDE editor support (IntelliSense), so I wondered if there were any tricks that could allow me to (perhaps) add multiple definitions and then include the file without to complete each line \

?

Something like:

// 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

      

And I would somehow get all the correct ones struct

and functions. The problem is that there is a lot of parameter concatenation in these macros, so I'm not sure if this can be done easier than the first snippet?

+3


source to share


2 answers


Not recommended in this case, but you can do something like what you want to achieve, X-macro :

#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

      

But that didn't improve the situation much. It got rid of the need for one, ugly macro Fifo_define

so that you can split your code into multiple sections. But the macro mess remains.




I would recommend a completely different approach. Two suggestions:

  • Process common things in classic C mode at runtime. Use callbacks. Track the used enumerated type as needed.

  • C11 _Generic

    allows all sorts of type safety tricks and can be used to phase out such dirty macros. An example that implements "functors" . The macro itself is kept minimal, and different implementations for different types are printed. (This is usually what you end up doing when you do sample programming.)

+1


source


If you are using complex macros, consider using m4 instead of a C pre-processor. M4 is similar to a C pre-processor, but much more powerful and can do something like multiple lines without a line-continuation character.

Using code generators like m4 is called metaprogramming .

Using m4 in C can be done by treating it as a pre-processor like this :



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

      

Since m4 works in a similar way to a C pre-processor at a basic level, it will usually convert any regular C macros in addition to supporting its own extended functionality.

+1


source







All Articles