Preliminary observations
You should note that the space between setfunc1
and the open parenthesis in:
#define setfunc1 (name,a8) a8
means that the name setfunc1
is an object-like macro, not a function-like macro. If you want (name, a8)
to be arguments to a function-like macro, the open parenthesis must not have any space (or comment) after the macro name when you define the macro. When you use the macro, you can have any amount of white space (including comments) between the macro name and its argument list, but not when defining the macro.
Defining INIT_METHODS
You can do what you want — though I still have major reservations about whether it is appropriate to do it.
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define INIT_METHODSP(name, count, ...) setfunc##count(name, __VA_ARGS__)
#define INIT_METHODEV(name, count, ...) INIT_METHODSP(name, count, __VA_ARGS__)
#define INIT_METHODS(name, ...) INIT_METHODEV(name, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#define setfunc2(p, m1, f1) p->m1 = f1
#define setfunc4(p, m1, f1, ...) setfunc2(p, m1, f1); setfunc2(p, __VA_ARGS__)
#define setfunc6(p, m1, f1, ...) setfunc2(p, m1, f1); setfunc4(p, __VA_ARGS__)
#define setfunc8(p, m1, f1, ...) setfunc2(p, m1, f1); setfunc6(p, __VA_ARGS__)
typedef struct{
void (*method1)(void);
}data1_t;
typedef struct{
void (*method1)(void);
void (*method2)(void);
}data2_t;
typedef struct{
void (*method1)(void);
void (*method2)(void);
void (*method3)(void);
void (*method4)(void);
}data4_t;
void function1(void){}
void function2(void){}
data1_t *ptr1 = calloc(sizeof(data1_t), 1));
data2_t *ptr2 = calloc(sizeof(data2_t), 1));
data2_t *ptr4 = calloc(sizeof(data4_t), 1));
INIT_METHODS(ptr1, method1, function1);
INIT_METHODS(ptr2, method1, function1, method2, function2);
INIT_METHODS(ptr4, method1, function1, method2, function2, method3, function3, method4, function4);
Explanation
The VA_NARGS_IMPL
and VA_NARGS
macros are unchanged apart from spacing or lack thereof.
The INIT_METHODEV
macro triggers evaluation (hence the EV
) of the count argument. Without this macro, you get to see expansions such as:
setfuncVA_NARGS(method1, function1)(ptr1, method1, function1);
which really isn't very helpful.
The setfuncN
macros have one pointer argument (p
) and N/2 pairs of arguments listing member and function to initialize it to. Note that there isn't a semicolon after the expansion of setfunc2
; that is provided by the semicolon after the invocation of INIT_METHODS
.
The generalization of the setfuncN
macros to more elements is straight-forward (though you'll need to modify VA_NARGS
and VA_NARGS_IMPL
to handle more arguments too).
The lines defining ptr1
etc were fixed to:
- Define pointers instead of structures.
- Use
sizeof()
correctly.
Also, all function pointers and definitions have strict prototypes. When you declare something like void (*method1)();
in C, you are defining a pointer to a function that returns void
but takes an indeterminate but not variadic argument list. (In C++, it would be a pointer to a function that takes no arguments, but this is C, not C++.) The 'not variadic' bit means that the function prototype would not contain ellipsis ...
. All functions that take a variadic argument list must have a full prototype in scope when used.
Output
$gcc -std=c99 -E vma2.c
# 1 "vma2.c"
# 1 "<command-line>"
# 1 "vma2.c"
# 13 "vma2.c"
typedef struct{
void (*method1)(void);
}data1_t;
typedef struct{
void (*method1)(void);
void (*method2)(void);
}data2_t;
typedef struct{
void (*method1)(void);
void (*method2)(void);
void (*method3)(void);
void (*method4)(void);
}data4_t;
void function1(void){}
void function2(void){}
data1_t *ptr1 = calloc(sizeof(data1_t), 1));
data2_t *ptr2 = calloc(sizeof(data2_t), 1));
data2_t *ptr4 = calloc(sizeof(data4_t), 1));
ptr1->method1 = function1;
ptr2->method1 = function1; ptr2->method2 = function2;
ptr4->method1 = function1; ptr4->method2 = function2; ptr4->method3 = function3; ptr4->method4 = function4;
$
This looks like what I think you wanted.
Note that the code passes the preprocessor; it won't pass the compiler proper as written because:
function3
andfunction4
are undeclared.- Assignments like the
calloc
calls must be in the body of a function. - The assignments that initialize the structures need to be in the body of a function too.