C / C ++需要一种聪明的方法来跟踪函数调用

我正在寻找一种聪明的方法来跟踪函数调用和返回。 我知道我可以使用调试器,但我希望有一种方法可以让它在调用函数时向终端输出一些东西而不必逐步执行代码。
我想我可以使用预处理器,但我不确定最好的方法是什么。
或者有没有办法使用gdb打印出有用的信息,而无需单步执行代码。

大多数编译器允许您在函数调用之前和之后注入检测函数。

在msvc中,它们是_penter和_pexit
好文章http://www.drdobbs.com/184403601

在gcc中你会使用-finstrument-functions
http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Code-Gen-Options.html

您可以使用调试库或映射文件来获取更多信息。

由于您使用的是GCC,因此您也可以使用链接器函数包装。

Link-Time Replacement / Wrapping – GCC option: -Wl,--wrap,function_name 

基本上,您可以使用名为“function_name()”的函数并使用名为“__wrap_function_name()”的函数对其进行包装。 您可以通过调用“__real_function_name()”来访问原始函数。

一个非常具有侵入性的解决方案是使用RAII来控制function的范围。 这将对性能产生很大影响,但在日志中将非常明确,而无需用户在可能离开函数的所有可能代码路径中添加检测:

 class ScopeLogger { public: ScopeLogger( std::string const & msg ) : msg(msg) { std::cout << "Enter: " << msg << std::endl; } ~ScopeLogger() { std::cout << "Exit: " << msg << std::endl; } std::string msg; }; #if DEBUG #define FUNCTION(x) ScopeLogger l_##x##_scope(x); #endif void foo( int value ) { FUNCTION( __FUNCTION__ ); if ( value > 10 ) throw std::exception; std::cout << "." << std::endl; } int main() { foo(0); // Enter: foo\n.\nExit: foo foo(100); // Enter: foo\nExit: foo } 

如果代码是单线程的,您甚至可能希望向ScopedLogger添加一个具有一些缩进级别的静态变量,而不会对已经很重的性能影响添加太多:

 class ScopeLogger { public: ScopeLogger( std::string const & msg ) : msg(msg) { std::cout << std::string(indent++,' ') << "Enter: " << msg << std::endl; } ~ScopeLogger() { std::cout << std::string(--indent,' ') << "Exit: " << msg << std::endl; } std::string msg; static int indent; }; int ScopeLogger::indent = 0; 
 #define BEGIN_FUNC(X) printf("Function %s Entered",X) #define END_FUNC(X) printf("Function %s End",X) foo() { BEGIN_FUNC(__func__); //Your code here END_FUNC(__func__); } 

我想如果你像上面那样写一个宏并将它用于所描述的每个函数,那么你可以在终端上获取日志。

您可能想要查看Valgrind的Callgrind ,它可以将函数调用跟踪到漂亮的图形中。 它将显示函数调用,但不显示参数或返回值。

或者有没有办法使用gdb打印出有用的信息,而无需单步执行代码

是。 仅在您真正关心的function上设置断点。 使用“继续”直到进入这些function或程序崩溃。 然后使用“backtrace”(或“bt”)来获得堆栈跟踪。

如果需要自动化,可以查看TARGET_ASM_FUNCTION_END_PROLOGUETARGET_ASM_FUNCTION_BEGIN_EPILOGUE 。 这些是编译器挂钩,可以让你指定要与正常函数prologue / epilogue一起发出的程序集 – 在你的情况下,你会使用它们发出一个小程序集来记录相关函数的入口/出口。 您还可以查看FUNCTION_PROFILE和/或PROFILE_HOOK (例如,请访问: http : //gcc.gnu.org/onlinedocs/gccint/Function-Entry.html )。

有一个__FUNCTION__ (引用)宏用于确定您所处的方法(格式为Class::Method ),但这更像是一个手动过程。

但是,当我最近需要相同的“跟踪”信息时,我找不到自动方法。

前段时间我听了一个关于面向方面编程的讨论 ,其中包括你想要实现的目标。 也许搜索该术语会有所帮助。