【问题标题】:How do I get the name of the calling function?如何获取调用函数的名称?
【发布时间】:2011-09-09 06:08:42
【问题描述】:

我正在使用 gnu 工具链。如何在运行时找到函数的调用者?即例如函数 B() 被许多函数使用函数指针调用。现在,每当 B 被呼叫时,我想打印呼叫者的姓名。我需要这个来调试某个问题。

【问题讨论】:

    标签: c gcc function-pointers


    【解决方案1】:

    Vasil Dimov 在回答类似问题时指出的另一种方法是将函数调用替换为报告或传入调用函数名称的包装宏。这将适用于内联函数,而回溯则不会。另一方面,如果您通过引用调用该函数,或者以其他方式获取其地址,则它将不起作用。

    例如:

    int B(int x){
        ...
    }
    

    可能变成:

    int _B(int x, char *caller){
        printf("caller is %s\n", caller);
        ...
    }
    
    #define B(x) _B((x), __func__)
    

    并且每次调用 B() 都会打印调用者的姓名。 Vasil Dimov 以不同的方式构造它,直接在宏中打印名称并保持函数不变。

    【讨论】:

    • 当使用函数指针调用函数时,这将不起作用。不能有指向 B(x) 的指针,因为它现在是宏而不是函数。所以我将不得不改用 _B(x) 但这将需要在每次使用指针调用函数时传递__func__,这违反了这个问题的整个想法。
    • @binW:这就是我所说的“如果你通过引用调用函数,或者以其他方式获取它的地址,它将不起作用
    【解决方案2】:

    调用函数的代码位置由 gcc 保存在 __builtin_return_address() 内在函数中。要为此检索 name,您必须解析程序的符号表;虽然可以通过dladdr() 做到这一点,但这是有限制的:

    1. 在所有上下文中调用backtrace()/dladdr() 可能并不安全(例如,从信号处理程序,或同时在多线程程序中,或从不能调用malloc() 的上下文中。)。
    2. 该操作不是即时的,但可能需要将调用线程置于睡眠状态;如果在调用时持有任何锁,这是一件坏事。
    3. 返回地址在名称中的“可解析性”是有限度的;例如如果有内联函数调用你的函数,那么 你的调用者的调用者 会出现(backtrace() 手册页也说明了这一点,dladdr() 在“BUGS”部分的说明也是如此) .
    4. 在 C++ 中,通过 con/destructors/initializers 调用会带来额外的挑战,其中函数的“调用者”最终可能是一些编译器生成的元代码,而您感兴趣的实际位置可能在其他地方(调用者的调用者,甚至更深的调用堆栈)。

    这通常是解耦跟踪和函数名称解析的更好方法;即只输出返回地址(作为十六进制/二进制),然后根据程序运行时检索到的符号表对生成的日志进行后处理。

    【讨论】:

      【解决方案3】:

      如果您使用的是 GNU,则可以使用 backtrace 函数。该手册页上有一个使用示例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-11
        相关资源
        最近更新 更多