The function name, return type, number and types of arguments should be variable.
There is no way of doing this with a single preprocessor macro. The problem lies in the fact that "the number of arguments should be variable". However... there's a solution which I believe achieves exactly what you want.
A classic example of getting around this issue is in the Linux kernel source code, where you can see different SYSCALL_DEFINE<n>
macros used to define syscalls with different numbers of arguments, like:
SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
{
return ksys_lseek(fd, offset, whence);
}
You can see how those macros are defined in include/linux/syscalls.h
. They are actually pretty convoluted, but at the end of the day the real magic is behind that __MAP(...)
macro defined for up to 6 arguments.
Similarly, you could do this:
#define MAP0(m,...)
#define MAP1(m,t,a,...) m(t,a)
#define MAP2(m,t,a,...) m(t,a), MAP1(m,__VA_ARGS__)
#define MAP3(m,t,a,...) m(t,a), MAP2(m,__VA_ARGS__)
// ... add more as needed
#define MAP(n,...) MAP##n(__VA_ARGS__)
#define DEFINE_ARG(argtype, argname) argtype argname
#define CALL_ARG(argtype, argname) argname
#define DEFINE1(...) DEFINEx(1, __VA_ARGS__)
#define DEFINE2(...) DEFINEx(2, __VA_ARGS__)
#define DEFINE3(...) DEFINEx(3, __VA_ARGS__)
// ... add more as needed
#define SIGNATUREx(x, rettype, funcname, ...) rettype funcname(MAP(x, DEFINE_ARG, __VA_ARGS__))
#define HOOKx(x, rettype, funcname, ...) \
static inline rettype funcname##_HOOKED(MAP(x, DEFINE_ARG, __VA_ARGS__)); \
\
SIGNATUREx(x, rettype, funcname, __VA_ARGS__) \
{ \
funcname##_PRE_HOOK(); \
rettype rval = funcname##_HOOKED(MAP(x, CALL_ARG, __VA_ARGS__)); \
funcname##_POST_HOOK(); \
return rval; \
} \
\
static inline rettype funcname##_HOOKED(MAP(x, DEFINE_ARG, __VA_ARGS__))
#ifdef COMPILER_SWITCH
#define DEFINEx(...) HOOKx(__VA_ARGS__)
#else
#define DEFINEx(...) SIGNATUREx(__VA_ARGS__)
#endif
Put the above in a separate hook.h
header file, and you'll have a pretty clean solution.
You can then define your functions like this:
#include "hook.h"
DEFINE1(int, foo, int, x)
{
return x + 1;
}
DEFINE2(float, bar, int, x, float, y)
{
return x + y;
}
The above produces the following if compiled with gcc -DCOMPILER_SWITCH
:
static inline int foo_HOOKED(int x);
int foo(int x) {
foo_PRE_HOOK();
int rval = foo_HOOKED(x);
foo_POST_HOOK();
return rval;
}
static inline int foo_HOOKED(int x)
{
return x + 1;
}
static inline float bar_HOOKED(int x, float y);
float bar(int x, float y)
{
bar_PRE_HOOK();
float rval = bar_HOOKED(x, y);
bar_POST_HOOK();
return rval;
}
static inline float bar_HOOKED(int x, float y)
{
return x + y;
}
And the following if compiled normally:
int foo(int x)
{
return x + 1;
}
float bar(int x, float y)
{
return x + y;
}