The key is, I think, to "factor out" the condition. For example, COND1
(or COND2 etc.) should surround the definition of the funcs
array, not vice versa. Here I assume that you can boil down your conditions to integer defines. That could be done e.g. by
#if COND1
# define N 1
#elif COND2
# define N 2
// ...
#endif
Let's also assume that you have several function stubs (not only func
) which are all expanded to stub<n>
-like names. Then you can fully parametrize your function name generation as follows. (The code makes use of string literal concatenation and of for loop variables. gcc -std=c99
compiles it fine.)
Main file. Declare the functions and define the description struct array.
#include<stdio.h>
// example struct definition
typedef struct { const char* description; int (*f)(void); } my_struct;
// A two-stage macro expansion is necessary because
// macro parameters are taken literally when used in
// concatenation or stringification
// (cf. https://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html)
// Expands to function declaration
#define X_LITERAL_PARAMS(fname, suffix) extern int fname ## suffix (void);
#define X(fname, suffix) X_LITERAL_PARAMS(fname, suffix) // this expands suffix e.g. to 1
// define extern int functions
#define N 1 // select which function variants
#include "xmacro_x.h"
#undef X_LITERAL_PARAMS
#define X_LITERAL_PARAMS(fname, suffix) { "Calling " #fname #suffix, fname ## suffix},
my_struct funcs[] = {
#undef N
#define N 1 // select which function variants
#include "xmacro_x.h"
// defines descriptions for functions
# include "xmacro_x.h"
};
// Print description and call each function
// in the struct array
int main(void)
{
for(int i=0; i<sizeof(funcs)/sizeof(my_struct); i++)
{
printf("%s yields %d\n\n", funcs[i].description, funcs[i].f());
}
return 0;
}
File funcs.c actually defines the functions.
// Define functions named as in the struct array
// for proof of concept
#include <stdio.h>
// two-stage expansion again
#define X_LITERAL_PARAMS(f, n) \
int f ## n (void){ return printf("This is %s\n", #f #n);}
#define X(a,b) X_LITERAL_PARAMS(a,b)
#define N 1
#include "xmacro_x.h"
Finally, the rather uninteresting file xmacro_x.h provides the "X macros" expanded to different code snippets in the source files. Here it introduces various "function families", name stubs which will be combined with the numeric suffixes later.
// The "X macros" which will be expanded to different things later
X(func, N)
X(gunc, N)
//...