经过多年使用丑陋的MFC ASSERT宏,我终于决定抛弃它并创建最终的ASSERT宏.
我很好地获取文件和行号,甚至是失败的表达式.我可以显示带有这些的消息框,以及中止/重试/取消按钮.
当我按下Retry时,VS调试器会跳转到包含ASSERT调用的行(而不像某些其他ASSERT函数那样反汇编).所以这一切都非常有效.
但真正酷的是显示失败的函数的名称.
然后我可以决定是否调试它而不试图从文件名中猜出它的功能.
例如,如果我有以下功能:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ASSERT(lpCreateStruct->cx > 0); ... }
然后当ASSERT触发时,消息框将显示如下内容:
Function = CMainFrame::OnCreate
那么,在运行时找到当前函数名的最简单方法是什么?
它不应该使用MFC或.NET框架,即使我确实使用这两者.
它应该尽可能便携.
您的宏可以包含__FUNCTION__
宏.毫无疑问,函数名称将在编译时插入到扩展代码中,但对于每次调用宏,它都是正确的函数名称.所以它"似乎"它在运行时发生;)
例如
#define THROW_IF(val) if (val) throw "error in " __FUNCTION__ int foo() { int a = 0; THROW_IF(a > 0); // will throw "error in foo()" }
C++预处理器宏__FUNCTION__
给出了函数的名称.
请注意,如果您使用此,它不是真正得到的文件名,行号,或函数在运行时的名称.宏由预处理器扩展,并编译.
在__FUNCTION__
宏象__LINE__
,并且__FILE__
,是语言标准的一部分,并且是便携式的.
示例程序:
#include#using namespace std; void function1() { cout << "my function name is: " << __FUNCTION__ << "\n"; } int main() { cout << "my function name is: " << __FUNCTION__ << "\n"; function1(); return 0; }
输出:
my function name is: main my function name is: function1
没有标准的解决方案.但是,BOOST_CURRENT_FUNCTION
可移植用于所有实际目的.标头不依赖于任何其他Boost标头,因此如果整个库的开销是不可接受的,则可以单独使用.
__FUNCTION__
或__FUNC__
或__PRETTY_FUNCTION__
http://msdn.microsoft.com/en-us/library/b0084kay(VS.80).aspx http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
在GCC中,您可以使用__PRETTY_FUNCTION__
宏.
微软也有一个等效的__func__
宏,虽然我没有可用的尝试.
例如,__PRETTY_FUNCTION__
在你的功能开始时使用这样的东西,你会得到一个完整的痕迹
void foo(char* bar){ cout << __PRETTY_FUNCTION__ << std::endl }
哪个会输出
void foo(char* bar)
如果要输出更多信息,还可以在所有标准c/c ++编译器下使用__FILE__
和__LINE__
宏.
在实践中,我有一个特殊的调试类,我使用而不是cout.通过定义适当的环境变量,我可以获得完整的程序跟踪.你可以做类似的事情.这些宏非常方便,能够在现场打开这样的选择性调试真的很棒.
编辑:显然__func__
是标准的一部分?不知道那个.不幸的是,它只提供函数名称而不是参数.我喜欢gcc,__PRETTY_FUNC__
但它不能移植到其他编译器.
GCC也支持__FUNCTION__
.
您可以使用在编译时将扩展为函数名称的__FUNCTION__
宏.
这是一个如何在断言宏中使用它的示例.
#define ASSERT(cond) \ do { if (!(cond)) \ MessageBoxFunction("Failed: %s in Function %s", #cond, __FUNCTION__);\ } while(0) void MessageBoxFunction(const char* const msg, ...) { char szAssertMsg[2048]; // format args va_list vargs; va_start(vargs, msg); vsprintf(szAssertMsg, msg, vargs); va_end(vargs); ::MessageBoxA(NULL, szAssertMsg, "Failed Assertion", MB_ICONERROR | MB_OK); }