How do I find the name of the calling function?
我一直在使用pretty_函数输出当前的函数名,但是我重新实现了一些函数,并想知道哪些函数正在调用它们。
在C++中,如何获取调用例程的函数名?
这里有一个您经常使用的解决方案。它的优点是不需要更改实际的函数代码(不需要添加对stackwalk函数的调用、更改参数以传入函数名或链接到其他库)。要使其正常工作,只需使用一些预处理器魔术:
简单实例1 2 3 4 5 6 7 8 9 | // orignal function name was 'FunctionName' void FunctionNameReal(...) { // Do Something } #undef FunctionName #define FunctionName printf("Calling FunctionName from %s ",__FUNCTION__);FunctionNameReal |
必须临时重命名函数,但有关更多建议,请参阅下面的注释。这将导致在调用函数的每个点都有一个
另外,您可能希望在头部放置类似这样的东西,由
我收到一个扩大我答案的请求。事实证明,我上面的例子有点简单。这里有一些完整的例子,用C++来处理。
带返回值的完整源代码示例使用
对于非报告版本,您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include <iostream> int FunctionName(int one, int two) { static int calls=0; return (++calls+one)*two; } #ifdef REPORT // class to capture the caller and print it. class Reporter { public: Reporter(std::string Caller, std::string File, int Line) : caller_(Caller) , file_(File) , line_(Line) {} int operator()(int one, int two) { std::cout <<"Reporter: FunctionName() is being called by" << caller_ <<"() in" << file_ <<":" << line_ << std::endl; // can use the original name here, as it is still defined return FunctionName(one,two); } private: std::string caller_; std::string file_; int line_; }; // remove the symbol for the function, then define a new version that instead // creates a stack temporary instance of Reporter initialized with the caller # undef FunctionName # define FunctionName Reporter(__FUNCTION__,__FILE__,__LINE__) #endif void Caller1() { int val = FunctionName(7,9); // <-- works for captured return value std::cout <<"Mystery Function got" << val << std::endl; } void Caller2() { // Works for inline as well. std::cout <<"Mystery Function got" << FunctionName(11,13) << std::endl; } int main(int argc, char** argv) { Caller1(); Caller2(); return 0; } |
样本输出(报告)
1 2 3 4 | Reporter: FunctionName() is being called by Caller1() in test.cpp:44 Mystery Function got 72 Reporter: FunctionName() is being called by Caller2() in test.cpp:51 Mystery Function got 169 |
基本上,在
1 2 3 4 | void Caller2() { std::cout <<"Mystery Function got" << Reporter(__FUNCTION__,"test.cpp",51)(11,13) << std::endl; } |
你可以看到
这有点复杂,但与前面的示例非常相似。我们不只是替换对函数的调用,而是替换类。
像上面的例子一样,您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #include <iostream> class ClassName { public: explicit ClassName(int Member) : member_(Member) {} int FunctionName(int one, int two) { return (++member_+one)*two; } private: int member_; }; #ifdef REPORT // class to capture the caller and print it. class ClassNameDecorator { public: ClassNameDecorator( int Member) : className_(Member) {} ClassNameDecorator& FunctionName(std::string Caller, std::string File, int Line) { std::cout <<"Reporter: ClassName::FunctionName() is being called by" << Caller <<"() in" << File <<":" << Line << std::endl; return *this; } int operator()(int one, int two) { return className_.FunctionName(one,two); } private: ClassName className_; }; // remove the symbol for the function, then define a new version that instead // creates a stack temporary instance of ClassNameDecorator. // FunctionName is then replaced with a version that takes the caller information // and uses Method Chaining to allow operator() to be invoked with the original // parameters. # undef ClassName # define ClassName ClassNameDecorator # undef FunctionName # define FunctionName FunctionName(__FUNCTION__,__FILE__,__LINE__) #endif void Caller1() { ClassName foo(21); int val = foo.FunctionName(7,9); // <-- works for captured return value std::cout <<"Mystery Function got" << val << std::endl; } void Caller2() { ClassName foo(42); // Works for inline as well. std::cout <<"Mystery Function got" << foo.FunctionName(11,13) << std::endl; } int main(int argc, char** argv) { Caller1(); Caller2(); return 0; } |
以下是示例输出:
1 2 3 4 | Reporter: ClassName::FunctionName() is being called by Caller1() in test.cpp:56 Mystery Function got 261 Reporter: ClassName::FunctionName() is being called by Caller2() in test.cpp:64 Mystery Function got 702 |
这个版本的要点是修饰原始类的类,以及返回对类实例引用的替换函数,允许
希望能帮助别人!
以下是两个选项:
您可以使用带有gnu backtrace函数的最新版本的glibc获得完整的stacktrace(包括调用函数的名称、模块和偏移量)。详情请参阅我的回答。这可能是最简单的事情。
如果这不是你想要的,那么你可以尝试libunwind,但它会涉及到更多的工作。
请记住,这不是您静态地可以知道的东西(比如漂亮的_函数);实际上,您必须遍历堆栈来找出调用您的函数。所以这在普通的调试打印文件中是不值得做的。不过,如果您想进行更为严肃的调试或分析,那么这可能对您有用。
对于GCC版本≥4.8,您可以使用
例子:
1 2 3 4 5 6 7 8 9 10 11 | #include <cstdio> void foobar(const char* str = __builtin_FUNCTION()){ std::printf("called by %s ", str); } int main(){ foobar(); return 0; } |
输出:
1 | called by main |
魔杖盒示例
除非问题比您明确要求的更多,否则只需重命名函数,让编译器/链接器告诉您调用它的位置。
亚伦回答的变化。我不确定这个答案是否有这个问题,但是当你做一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <iostream> struct ClassName { int member; ClassName(int member) : member(member) { } int secretFunctionName( int one, int two, const char* caller, const char* file, int line) { std::cout <<"Reporter: ClassName::function_name() is being called by" << caller <<"() in" << file <<":" << line << std::endl; return (++member+one)*two; } }; #define unique_global_function_name(first, second) \ secretFunctionName(first, second, __FUNCTION__,__FILE__,__LINE__) void caller1() { ClassName foo(21); int val = foo.unique_global_function_name(7, 9); std::cout <<"Mystery Function got" << val << std::endl; } void caller2() { ClassName foo(42); int val = foo.unique_global_function_name(11, 13); std::cout <<"Mystery Function got" << val << std::endl; } int main(int argc, char** argv) { caller1(); caller2(); return 0; } |
结果:
1 2 3 4 | Reporter: ClassName::function_name() is being called by caller1() in D:\test.cpp:26 Mystery Function got 261 Reporter: ClassName::function_name() is being called by caller2() in D:\test.cpp:33 Mystery Function got 702 |
您可以使用此代码跟踪程序中最后n个点的控制位置。用法:见下面的主要功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | // What: Track last few lines in loci of control, gpl/moshahmed_at_gmail // Test: gcc -Wall -g -lm -std=c11 track.c #include <stdio.h> #include <string.h> #define _DEBUG #ifdef _DEBUG #define lsize 255 /* const int lsize=255; -- C++ */ struct locs { int line[lsize]; char *file[lsize]; char *func[lsize]; int cur; /* cur=0; C++ */ } locs; #define track do {\ locs.line[locs.cur]=__LINE__ ;\ locs.file[locs.cur]=(char*)__FILE__ ;\ locs.func[locs.cur]=(char*) __builtin_FUNCTION() /* __PRETTY_FUNCTION__ -- C++ */ ;\ locs.cur=(locs.cur+1) % lsize;\ } while(0); void track_start(){ memset(&locs,0, sizeof locs); } void track_print(){ int i, k; for (i=0; i<lsize; i++){ k = (locs.cur+i) % lsize; if (locs.file[k]){ fprintf(stderr,"%d: %s:%d %s ", k, locs.file[k], locs.line[k], locs.func[k]); } } } #else #define track do {} while(0) #define track_start() (void)0 #define track_print() (void)0 #endif // Sample usage. void bar(){ track ; } void foo(){ track ; bar(); } int main(){ int k; track_start(); for (k=0;k<2;k++) foo(); track; track_print(); return 0; } |
在FIRS近似中,只需对函数名的代码基进行grep。然后是doxygen,然后是动态日志(这两个都由其他人讨论)。
您可能需要所有可能调用它们的函数的名称。这基本上是调用图中的一组边。Doxygen可以生成调用图,然后只需查看函数节点的传入边缘即可。