Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get last function called in C/C++

Tags:

c++

c

function

api

I'm using an API and I find myself writing a lot of error-handling code of the general form:

if (errorCode = functionName(params)) 
    printError(errorCode, "functionName", __LINE__, __FILE__);

where the body of printError might look like:

fprintf(stderr, "Error in function %s on line %d of file %s", 
    functionName, lineNumber, fileNumber);

However, it's a pain to hard-code the function name every time. Is there any way to get the name of the function causing the error, i.e. the last function called, either at runtime or through a macro? I can't modify the API function in any way, of course. There are ways to get the current function as well as the calling function, but neither of these work from outside the function.

like image 201
1'' Avatar asked May 16 '13 00:05

1''


2 Answers

you can have this

#define SAFE_CALL(func) \
do {\
    if (errorCode = (func)) \
        printError(errorCode, #func, __LINE__, __FILE__);\
} while(0)

SAFE_CALL(functionName(params));
like image 111
Bryan Chen Avatar answered Sep 27 '22 15:09

Bryan Chen


The solution here is to make a macro that invokes your function, and if it fails, invoke a print function with your special parameters. If you're using C99, then you can (ab)use a variadic macro, like this:

void printError(const char *fmt, const char *func, const int line, const char *file, ...) {
    // the first three arguments are our function, line and file, so first, print out that first
    va_list list;
    va_start(list, file);

    // only print until the first '('
    int nchars = (int) (strchr(func, '(') - func);

    fprintf(stderr, "Error in function %.*s on line %d of file %s: ", nchars, func, line, file);
    vfprintf(stderr, fmt, list);

    va_end(list);
}

#define checkError(invoke, fmt, ...)\
do {\
    int err;\
    if ((err = (invoke))) {\
        printError(fmt, #invoke, __LINE__, __FILE__, ## __VA_ARGS__);\
    }\
} while(0)

Note that the above makes use of a GCC extension (which is also supported in clang) which allows for variadic arguments to be properly passed if none were provided.

Which could then be used as such:

checkError(fail(), "Couldn't validate results: %s", "Context-Sensitive Debug Info");

Which outputs this lovely text for your debugging pleasure:

Error in function fail on line 703 of file /Users/rross/Documents/TestProj/TestProj/main.mm: Couldn't validate results: Context-Sensitive Debug Info

You may want to play around with other macros, such as GCC/Clang's __PRETTY_FUNCTION__, but this should get you started!

like image 45
Richard J. Ross III Avatar answered Sep 27 '22 16:09

Richard J. Ross III