Question
I have a method to wrap functions by replacing them with a macro so that I can log the call and the return code. Here's an example which works:
int rc;
int foo(int a, int b);
int bar(int a, char *b, int *c);
void LogRet(char *fn, char *file, char *from, int ln, int ret)
{
printf("%s.%s.%d: %s() ret:%08x\n", file, from, ln, fn, ret);
}
#define foo(args, ...) (rc = (foo)(args, ##__VA_ARGS__), LogRet("foo", __FILE__, __FUNCTION__, __LINE__, rc), rc)
#define bar(args, ...) (rc = (bar)(args, ##__VA_ARGS__), LogRet("bar", __FILE__, __FUNCTION__, __LINE__, rc), rc)
The macro for the function it substitutes calls the function and logs the function name and where it was called from as well as the return code. Wrapping any function uses the same syntax and just needs the function name replaced in the macro 3 times. What I would like to do is create wrapper macro where the macro redefine for foo would be something similar to:
#define foo(args, ...) WRAPPPER(foo)
I understand the basics of stringify and double stringify but I can't even get the WRAPPER macro to do the real function call. Ideally, I'd like to get it down to single WRAP(foo) statement. The reason is, I have around 100 or more functions I'd like to wrap and it would like to do it simple from one simple force include file. I'm coming to the conclusion that it's not possible but I thought I'd ask here before abandoning the idea. I'm using clang and vc++ if that makes any difference but it would be nice to have this on any compiler as I debug a lot of different systems.
Adaptation of Jonathan Leffler's answer
As I'm new here I wasn't sure if this should be a separate answer or and edit update. This is essentially Jonathan Leffler's answer. It's in a functional example. While the 2 functions it calls are pointless, the goal was to have a macro that could wrap any function with any arg list. My main use is in logging the use flow in a large code library that has a problem. Also, my original sample has one glaring weakness. By storing the return code in a global it is not thread safe without cumbersome preparation in TLS. The global is now removed and the macro no longer uses the sequence operator to return the value, it is preserved and returned by the logging function. Also, as Augurar pointed out and shown in Jonathan's example. If the macro is declared in the same file as the function declaration, it requires parentheses.
#include <stdio.h>
#include <string.h>
int foo(int a, int b);
int bar(int a, char *b, int *c);
#if defined (_DEBUG) || defined (DEBUG)
// Short version of __FILE__ without path requires runtime parsing
#define __SFILE__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#ifdef WIN32
#define WRAPPER(func, ...) LogRet(#func, __SFILE__, __FUNCTION__, __LINE__, (func)(__VA_ARGS__))
#else
#define WRAPPER(func, ...) LogRet(#func, __SFILE__, __func__, __LINE__, (func)(__VA_ARGS__))
#endif
inline int LogRet(const char *fn, const char *file, const char *from, int ln, int ret)
{
printf("%s.%s.%d: %s() ret:%08x\n", file, from, ln, fn, ret);
return ret;
}
#define foo(...) WRAPPER(foo, __VA_ARGS__)
#define bar(...) WRAPPER(bar, __VA_ARGS__)
#endif
int main(void)
{
int x = foo(1, 2);
bar(2, "doubled", &x);
return 0;
}
#ifdef foo
#undef foo
#undef bar
#endif
// If and only if the function definition is in the same file with the macros, you must either undefine the macros or
// parenthesize the function e.g. int (foo)(int a, int b) { ... }
int foo(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
return a + b;
}
int (bar)(int a, char *b, int *c)
{
printf("%d %s = %d\n", *c, b, a * *c);
return *c * a;
}
Release build output:
1 + 2 = 3
3 doubled = 6
Debug build output:
1 + 2 = 3
test.cpp.main.35: foo() ret:00000003
3 doubled = 6
test.cpp.main.36: bar() ret:00000006
The main benefit is not having to find every occurrence of foo() or bar() in the code to insert a debug print to log the call and result or whatever debug code you want to insert.
foo
macro is recursively defined. Also, including your attempted definition ofWRAPPER
(even if unsuccessful) would be helpful. – augurar