You pretty much describe "X-macros", which would be preferred "design pattern" to use here instead of cooking up some custom macro solution. Normally you'd make a plain X-macro something like this:
#define DEF(X) \
X(foo) \
X(bar) \
X(baz)
Which might then be used to create for example an enum or whatever:
#define DEF_ENUM(name) name,
typedef enum
{
DEF(DEF_ENUM)
def_n // placed here to count the number of items in the list
} def_t;
Now suppose that we also want to add an additional parameter to mark if a certain value should be used or not. There's various ways to do that, I'll use C23 __VA_OPT__ in this example. We can then tweak the above X-macro list to this:
#define DEF(X) \
X(foo, function) \
X(bar, function) \
X(baz)
Where function can be any valid pre-processor token - doesn't matter in this case.
When defining the function, we just check if there's an additional argument present or not by writing a macro where the last parameter is variadic. If there isn't a last parameter present, then __VA_OPT__ will discard whatever we placed inside it:
#define DEF_FUNCTIONS(name, ...) \
__VA_OPT__( void name##_func (void){ puts(__func__); } )
DEF(DEF_FUNCTIONS)
Full example:
#include <stdio.h>
#define DEF(X) \
X(foo, function) \
X(bar, function) \
X(baz)
#define DEF_ENUM(name,...) name,
typedef enum
{
DEF(DEF_ENUM)
def_n
} def_t;
#define DEF_FUNCTIONS(name, ...) \
__VA_OPT__( void name##_func (void){ puts(__func__); } )
DEF(DEF_FUNCTIONS)
int main()
{
puts("The enumeration constants and their values: ");
#define PRINT_ENUM(name,...) printf("%s: %d\n", #name, name);
DEF(PRINT_ENUM)
printf("(There are %d of them)\n\n", def_n);
puts("Call some functions:");
foo_func();
bar_func();
//baz_func(); will not compile since it isn't defined
}
Output:
The enumeration constants and their values:
foo: 0
bar: 1
baz: 2
(There are 3 of them)
Call some functions:
foo_func
bar_func
#define DONT_DEF_bazcome from? Can't you modify the generation of the file withDEF(foo)etc to omit the lineDEF(baz)? Or wrap allDEF(foo)in suitable#ifndef DONT_DEF_fooby the generation, maybe by adding a post-processing? Why is it necessary to omit the declaration of a function?