Sedmaister
Sedmaister

Reputation: 585

How to find which function is calling another function in C?

Let's say I have a function called verify() inside verify.c and it is used to evaluate a condition and print debug message if the check fails.

void verify(int expected)
{
    if (expected < 10) {
        fprintf(stderr,"Verification failed for %d\n", expected);
        abort();
    }
}

Now, I am adding this header file verify.h in various c files throughout SW package, and many functions from different c files are calling verify(). If the check fails, verify() will print out the error message but how do I exactly find out where it is happening (i.e. which file and which function is actually calling failed verify())?

I want to find this during I compile my code and without using a debugger such as gdb.

Upvotes: 1

Views: 1341

Answers (3)

Clifford
Clifford

Reputation: 93476

Given verify.h declaring:

#define verify(e) verify_impl( (e), __FILE__, __func__, __LINE__ )
void verify_impl( int expected, const char* file, const char* fn, int line ) ;

And verify.c defining:

void verify_impl(int expected, const char* file, const char* fn, int line ) ; )
{
    if (expected < 10) 
    {
        fprintf( stderr,"Verification failed for %d at %s:%s(%d)\n",
                 expected, file, fn, line );
        abort();
    }
}

The when verify(9) ; is called from foo() at line 20 of bar.c for example, you will get:

Verification failed for 9 at bar.c:foo(20)

However a more generally useful assertion mechanism is possible. Consider:

verify.h:

#define verify(e) verify_impl( (e), #e, __FILE__, __func__, __LINE__ )
void verify_impl( int exp, const char* expression, 
                  const char* file, const char* fn, int line ) ;

verify.c

void verify_impl( int exp, const char* expression, 
                  const char* file, const char* fn, int line ) ; )
{
    if( !exp ) 
    {
        fprintf( stderr,"Verification that %s failed at from %s:%s(%d)\n",
                 expression, file, fn, line );
        abort();
    }
}

Then when verify( x >= 10 ) ; is called with x == 9 from foo() at line 20 of bar.c for example, you will get the more useful:

Verification that x >= 10 failed at bar.c:foo(20)

Any Boolean expression can be verified rather than the hard coded exp < 10. If you still need the original hard test, then you can define another macro in terms of the new more flexible one:

#define verify_notlessthan10( e ) verify( (e) >= 10 )

Note the inversion of the logic; you are verifying that the expression is true, and aborting when false. The semantics being that of assert.

Upvotes: 4

klutt
klutt

Reputation: 31316

One solution is to modify the code like this:

void verify(int expected, char * str)
{
    if (expected < 10) {
        fprintf(stderr,"Verification failed for %d\n", expected);
        if(str) 
            fprintf(stderr, str);
        abort();
    }
}

With this approach, you'll need to modify all calls. A way to get around that is to rename the function to verify_aux or something, and then write this:

void verify(int expected)
{
    verify_aux(expected, NULL);
}

This way, you could change verify to verify_aux if you feel the need to do so at a particular point.

Upvotes: 0

Jim Lewis
Jim Lewis

Reputation: 45045

If you're using gcc, you should be able to use the __FILE__, __LINE__, and __FUNCTION__ preprocessor macros, and pass them to your verify() routine to issue more useful debugging messages. As tadman points out in his comment, it might make sense to define a macro that acts as a wrapper for verify(), capturing the file, line, and function information before passing it to verify(). Then, at the point of use, you only need to call the wrapper and pass in the expected argument, letting the preprocessor fill in the extra information while it's still available in context, then passing it all to your verify() function.

Upvotes: 3

Related Questions