I want a function which achieves something like the behavior shown in the pseudo C code listed. I figure that this might be possible via the use of function pointers?
If this pattern I've dreamed up is terrible/impossible to implement, I'm more than happy to accept alternatives as an answer if it achieves the same kind of functionality.
void log_func(const char* name, /*other args*/) {
printf("called function: %s\n", name);
if (/*calling function exited*/)
printf("exited function: %s\n", name);
}
void example_func() {
log_func(__func__); // __func__ macro is expanded to be function name as a c-string
printf("This function does nothing\n");
}
output:
called function: example_func
This function does nothing
exited function: example_func
CodePudding user response:
Something like this works for functions returning void. Would have to be more clever for arbitrary returns.
#include<stdio.h>
#define WRAPPER
#ifdef WRAPPER
#define LOG_FUNC(fname, ...) \
do { \
printf("called function: %s\n", #fname); \
fname(__VA_ARGS__); \
printf("exited function: %s\n", #fname); \
} while(0)
#else
#define LOG_FUNC(fname, ...) \
fname(__VA_ARGS__)
#endif
void phello(int n, char *s) {
for(int i=0; i<n; i ) {
printf("%s\n", s);
}
}
int main()
{
LOG_FUNC(phello, 3, "Hello, World!");
}
Output
called function: phello
Hello, World!
Hello, World!
Hello, World!
exited function: phello
CodePudding user response:
If you need to do this for debugging in gcc, the GCC Function Instrumentation feature can help.
An example:
/* demo.c */
void example_func_2(void)
{
}
void example_func_1(void)
{
example_func_2();
}
int main(void)
{
example_func_1();
return 0;
}
/* instrument.c */
#include <stdio.h>
#include <dlfcn.h>
void __attribute__((no_instrument_function)) __cyg_profile_func_enter(void *callee, void *caller)
{
Dl_info info;
printf("Entering:");
if (dladdr(callee, &info))
{
printf(" callee : %-20s", info.dli_sname ? info.dli_sname : "<unknown>");
}
if (dladdr(caller, &info))
{
printf(" caller : %s", info.dli_sname ? info.dli_sname : "<unknown>");
}
printf("\n");
}
void __attribute__((no_instrument_function)) __cyg_profile_func_exit(void *callee, void *caller)
{
Dl_info info;
printf("Exiting: ");
if (dladdr(callee, &info))
{
printf(" callee : %-20s", info.dli_sname ? info.dli_sname : "<unknown>");
}
if (dladdr(caller, &info))
{
printf(" caller : %s", info.dli_sname ? info.dli_sname : "<unknown>");
}
printf("\n");
}
Compile with:
gcc -Wall -Wpedantic -Wextra -finstrument-functions -export-dynamic -D_GNU_SOURCE demo.c instrument.c -o demo -ldl
Run the program:
./demo
The ouput is:
Entering: callee : main caller : <unknown>
Entering: callee : example_func_1 caller : main
Entering: callee : example_func_2 caller : example_func_1
Exiting: callee : example_func_2 caller : example_func_1
Exiting: callee : example_func_1 caller : main
Exiting: callee : main caller : <unknown>