如何找到哪个函数正在C中调用另一个函数?

时间:2018-11-02 17:36:44

标签: c debugging

假设我在verify()内有一个名为verify.c的函数,它用于评估条件并在检查失败时打印调试消息。

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

现在,我将在整个SW软件包的各个c文件中添加此头文件verify.h,并且来自不同c文件的许多函数都在调用verify()。如果检查失败,verify()将打印出错误消息,但是我如何确切地找出错误的根源(即哪个文件和哪个函数实际上调用失败verify())?

我想在编译代码时找到它,而不使用gdb之类的调试器。

3 个答案:

答案 0 :(得分:3)

如果使用的是gcc,则应该能够使用__FILE__, __LINE__, and __FUNCTION__预处理程序宏,并将它们传递给verify()例程以发出更有用的调试消息。正如塔德曼(tadman)在其评论中指出的那样,定义一个宏作为verify()的包装器,在将文件,行和函数信息传递给verify()之前,可能会有意义。然后,在使用时,您只需要调用包装器并传递expected参数,让预处理器在上下文中仍可用的情况下填充额外的信息,然后将其全部传递给{{1 }}功能。

答案 1 :(得分:3)

给出verify.h声明:

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

然后对verify.c进行定义:

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();
    }
}

例如,在bar.c的第20行从verify(9) ;调用foo()时,您将得到:

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

但是,更通用的断言机制是可能的。考虑:

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();
    }
}

例如,当在bar.c的第20行从verify( x >= 10 ) ;x == 9调用foo()时,您会得到更多的帮助:

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

可以验证任何布尔表达式,而不是硬编码的exp < 10。如果仍然需要原始的硬测试,则可以根据新的更灵活的宏定义另一个宏:

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

请注意逻辑的反转;您正在验证表达式为 true ,并且在 false 时中止。语义是 assert 的语义。

答案 2 :(得分:0)

一种解决方案是像这样修改代码:

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

使用这种方法,您将需要修改所有呼叫。一种解决方法是将函数重命名为verify_aux或类似的名称,然后编写以下代码:

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

这样,如果您需要在特定时间点将验证更改为verify_aux。