__func__ 和 __PRETTY_FUNCTION__ 之间有什么区别?

6
我使用 g++ 4.8.1 并使用这两个宏进行调试。然而,__func__ 宏只给出函数名,当你有多个不同类中的相同名称函数时可能会误导。 __PRETTY_FUNCTION__ 宏生成整个函数签名 - 包括返回类型、类名和所有参数,可能非常长。
我希望能够在二者之间找到一种方法 - 一个宏,只给出类名和函数名。有没有办法实现这一点?

假设您在非静态成员函数中,您可以使用this的类型,typeid和http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html来获取类名。 - Marc Glisse
2
类名和函数名并不总是能唯一标识函数。 - Keith Thompson
1
@KeithThompson - 我能接受这个,我不需要100%的精确度 - 这只是调试。 - HEKTO
1
我发现 __FILE__ "(" STRINGIZE(__LINE__) "): " __func__ " - " 很好用,_特别是_在 MSVC 中,它能够识别这种语法。 - Mooing Duck
1
顺便说一下,__func__不是宏,这就是为什么它是小写的。 - HolyBlackCat
2个回答

8

灵感来自这里,我创建了以下宏__COMPACT_PRETTY_FUNCTION__

std::string computeMethodName(const std::string& function, const std::string& prettyFunction);

#define __COMPACT_PRETTY_FUNCTION__ computeMethodName(__FUNCTION__,__PRETTY_FUNCTION__).c_str() //c_str() is optional


std::string computeMethodName(const std::string& function, const std::string& prettyFunction) {
    size_t locFunName = prettyFunction.find(function); //If the input is a constructor, it gets the beginning of the class name, not of the method. That's why later on we have to search for the first parenthesys
    size_t begin = prettyFunction.rfind(" ",locFunName) + 1;
    size_t end = prettyFunction.find("(",locFunName + function.length()); //Adding function.length() make this faster and also allows to handle operator parenthesys!
    if (prettyFunction[end + 1] == ')')
        return (prettyFunction.substr(begin,end - begin) + "()");
    else
        return (prettyFunction.substr(begin,end - begin) + "(...)");
}

功能:

  • 获取__PRETTY_FUNCTION__
  • 删除返回类型和所有参数
  • 如果函数没有参数,则追加(),否则追加(...)

特点:

  • 处理命名空间,构造函数等
  • 还可以使用括号运算符!

限制:

  • 仅适用于gcc
  • 在运行时创建而不是编译时
  • 堆分配。
  • 不适用于lambda表达式,__FUNCTION____PRETTY_FUNCTION__不匹配......我几乎会称其为编译器错误 :)
    • __FUNCTION__查看一个operator()
    • __PRETTY_FUNCTION__看到的是<lambda(...)>

2
限制:在运行时创建而不是编译时创建,并且是堆分配的。 - Mooing Duck
@MooingDuck 有没有什么方法可以避免这种情况,例如在C++11中使用constexpr?你能帮我解决这个问题吗?(在我的情况下,这并不是很重要,因为只在调试期间使用)。 - Antonio
好吧,如果您很狡猾,您可能会添加一些超级复杂的东西来将名称放入编译时的“缓冲区”,但这很困难,我可能不会费心。 但是,我会修改computeMethodName尽可能使用const char(&)[N]来减少堆分配的数量。 我会快速解决这个问题。 - Mooing Duck
1
你的代码似乎也适用于相当复杂的情况!http://coliru.stacked-crooked.com/a/8d2dd99099c813f0 但不适用于病态案例:http://coliru.stacked-crooked.com/a/6a09d229735cfc72 - Mooing Duck
1
制作了一个零分配版本,尽管方法名称仅在同一线程的下一次调用之前有效。我认为这是可以接受的。http://coliru.stacked-crooked.com/a/132eb50d00b4cb7f 虽然不能完全正确地处理病态案例,但效果还不错。 - Mooing Duck
显示剩余4条评论

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接