43

经过多年使用丑陋的大 MFC ASSERT 宏,我终于决定放弃它并创建终极 ASSERT 宏。

我可以获取文件和行号,甚至是失败的表达式。我可以显示一个带有这些的消息框,以及中止/重试/取消按钮。

当我按下 Retry 时,VS 调试器会跳转到包含 ASSERT 调用的行(而不是像其他一些 ASSERT 函数那样的反汇编)。所以这一切都非常有效。

但真正酷的是显示失败的函数的名称

然后我可以决定是否调试它,而无需尝试从文件名中猜测它所在的函数。

例如,如果我有以下功能:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   ASSERT(lpCreateStruct->cx > 0);
   ...
}

然后当 ASSERT 触发时,消息框会显示如下内容:

Function = CMainFrame::OnCreate

那么,在运行时找出当前函数名称的最简单方法是什么?

它不应该使用 MFC 或 .NET 框架,即使我确实使用了这两者。
它应该尽可能便携。

4

7 回答 7

59

您的宏可以包含__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()"
}
于 2009-03-24T20:05:51.760 回答
26

C++ 预处理器宏__FUNCTION__给出了函数的名称。

请注意,如果您使用它,它并不会在运行时真正获取文件名、行号或函数名。宏由预处理器扩展,并编译进去。

__FUNCTION__宏,like__LINE____FILE__,是语言标准的一部分,并且是可移植的。

示例程序:

#include <iostream>
#using namespace std;

void function1()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
}
int main()
{
        cout << "my function name is: " << __FUNCTION__ << "\n";
        function1();
        return 0;
}

输出:

我的函数名称是:main
我的函数名称是:function1
于 2009-03-24T20:13:37.063 回答
18

没有标准的解决方案。但是,BOOST_CURRENT_FUNCTION对于所有实际目的都是便携式的。该标头不依赖于任何其他 Boost 标头,因此如果整个库的开销不可接受,则可以独立使用。

于 2009-03-24T21:32:08.467 回答
11

__FUNCTION____FUNC____PRETTY_FUNCTION__

http://msdn.microsoft.com/en-us/library/b0084kay(VS.80).aspx http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html

于 2009-03-24T20:07:38.840 回答
9

在 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__.

于 2009-07-23T22:05:51.553 回答
5

您可以使用在编译时将扩展为函数名称的__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);
}
于 2009-03-24T20:14:54.297 回答
1

您可以轻松使用func。它会在运行时取回你当前的函数名,这会引发异常。

用法:

cout << __func__ << ": " << e.what();
于 2019-03-24T22:16:46.063 回答