C语言 如何获取调用函数的名称?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6251787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I get the name of the calling function?
提问by binW
I am using gnu tool chain. How can I, at run time, find caller of a function? i.e for example function B() gets called by many functions using function pointers. Now, whenever B gets called, I want to print the callers name. I need this for debugging a certain issue.
我正在使用 gnu 工具链。如何在运行时找到函数的调用者?例如,函数 B() 被许多使用函数指针的函数调用。现在,每当 B 被调用时,我想打印调用者姓名。我需要这个来调试某个问题。
采纳答案by richq
回答by FrankH.
The code locationof the call to your function is kept by gcc in the __builtin_return_address()intrinsic. To retrieve the namefor that, you have to parse the program's symbol table; while that is possible to do, via dladdr(), there are limits to this:
调用函数的代码位置由 gcc 保存在__builtin_return_address()内部函数中。要检索它的名称,您必须解析程序的符号表;虽然这是可能的,但通过dladdr(),这有限制:
- it might not be safe in all contexts to call
backtrace()/dladdr()(like, from signal handlers, or concurrently in a multithreaded program, or from contexts where you can't callmalloc().). - the operation is not instant but might require putting the calling thread to sleep; this is a bad thing if at the point of the call any locks are held.
- there's limits to how well "resolvable" a return address is into a name; e.g. if there are inlined functions calling your function then the caller of your callerwould show up (the
backtrace()manpage states this as well, as does the one fordladdr()in the "BUGS" section). - In C++, there's the additional challenge of calls through con/destructors/initializers, where the "caller" of your function may end up being some compiler-generated metacode, and the actual place you're interested in could be elsewhere (caller of caller, or even deeper in the call stack).
- 在所有上下文中调用
backtrace()/可能并不安全dladdr()(例如,从信号处理程序中,或在多线程程序中同时调用,或从不能调用malloc(). 的上下文中)。 - 该操作不是即时的,但可能需要将调用线程置于睡眠状态;如果在调用时持有任何锁,这是一件坏事。
- 返回地址在名称中“可解析”的程度是有限的;例如,如果有内联函数调用您的函数,那么您的调用者的调用者就会出现(
backtrace()联机帮助页也说明了这一点,dladdr()“BUGS”部分中的说明也是如此)。 - 在 C++ 中,还有通过 con/destructors/initializers 调用的额外挑战,其中函数的“调用者”最终可能是一些编译器生成的元代码,而您感兴趣的实际位置可能在其他地方(调用者的调用者) ,甚至在调用堆栈中更深)。
It's often a better way to decoupletracing and function name resolving; i.e. just output the return addresses (as hex / binary) and then postprocess the resulting log against a symbol table retrieved when the program was running.
它通常是将跟踪和函数名称解析解耦的更好方法;即只输出返回地址(作为十六进制/二进制),然后根据程序运行时检索到的符号表对结果日志进行后处理。
回答by Douglas Bagnall
Another method, pointed out by Vasil Dimovin answer to a similar question, is to replace the function call with a wrapper macro that reports or passes in the calling function name. This will work with inline functions, where backtrace won't. On the other hand it won't work if you call the function by reference, or otherwise take its address.
Vasil Dimov在回答类似问题时指出的另一种方法是将函数调用替换为报告或传入调用函数名称的包装宏。这将适用于内联函数,而回溯则不会。另一方面,如果您通过引用调用该函数或以其他方式获取其地址,则它将不起作用。
For example this:
例如这个:
int B(int x){
...
}
could become:
可以变成:
int _B(int x, char *caller){
printf("caller is %s\n", caller);
...
}
#define B(x) _B((x), __func__)
and every call to B() will print the callers name. Vasil Dimov constructs it differently, printing the name directly in the macro and leaving the function unchanged.
每次调用 B() 都会打印调用者的名字。Vasil Dimov 以不同的方式构造它,直接在宏中打印名称并保持函数不变。

