269

__PRETTY_FUNCTION__, __FUNCTION__,和它们之间的区别是__func__什么?它们在哪里记录?我如何决定使用哪一个?

4

5 回答 5

312

__func__是一个隐式声明的标识符,当它在函数内部使用时扩展为包含函数名称的字符数组变量。它在 C99 中被添加到 C 中。从C99 §6.4.2.2/1 开始:

标识符__func__由翻译器隐式声明,就好像紧跟在每个函数定义的左大括号之后,声明

static const char __func__[] = "function-name";

出现,其中 function-name 是词法封闭函数的名称。该名称是函数的朴素名称。

请注意,它不是宏,在预处理过程中没有特殊含义。

__func__在 C++11 中被添加到 C++,其中它被指定为包含“一个实现定义的字符串”(C++11 §8.4.1[dcl.fct.def.general]/8),这并不完全是作为 C 中的规范很有用。(添加__func__到 C++的原始提议是N1642)。

__FUNCTION__是一些 C 编译器支持的预标准扩展(包括 gcc 和 Visual C++);一般来说,你应该__func__在支持的地方使用它,并且只__FUNCTION__在你使用不支持它的编译器时使用(例如,Visual C++,它不支持 C99 并且还不支持所有 C++0x,不支持提供__func__)。

__PRETTY_FUNCTION__是一个 gcc 扩展,与 基本相同__FUNCTION__,除了对于 C++ 函数,它包含函数的“漂亮”名称,包括函数的签名。Visual C++ 有一个类似(但不完全相同)的扩展名,__FUNCSIG__.

对于非标准宏,您需要查阅编译器的文档。Visual C++ 扩展包含在 C++ 编译器的“预定义宏”的 MSDN 文档中。gcc 文档扩展在 gcc 文档页面“函数名称作为字符串”中进行了描述。

于 2010-12-08T06:40:32.317 回答
145

尽管没有完全回答最初的问题,但这可能是大多数谷歌搜索的人想要看到的。

对于海湾合作委员会:

$ cat test.cpp 
#include <iostream>

int main(int argc, char **argv)
{
    std::cout << __func__ << std::endl
              << __FUNCTION__ << std::endl
              << __PRETTY_FUNCTION__ << std::endl;
}
$ g++ test.cpp 
$ ./a.out 
main
main
int main(int, char**)
于 2014-11-13T11:29:10.517 回答
69

__PRETTY_FUNCTION__处理 C++ 特性:类、命名空间、模板和重载

主文件

#include <iostream>

namespace N {
    class C {
        public:
            template <class T>
            static void f(int i) {
                (void)i;
                std::cout << "__func__            " << __func__ << std::endl
                          << "__FUNCTION__        " << __FUNCTION__ << std::endl
                          << "__PRETTY_FUNCTION__ " << __PRETTY_FUNCTION__ << std::endl;
            }
            template <class T>
            static void f(double f) {
                (void)f;
                std::cout << "__PRETTY_FUNCTION__ " << __PRETTY_FUNCTION__ << std::endl;
            }
    };
}

int main() {
    N::C::f<char>(1);
    N::C::f<void>(1.0);
}

编译并运行:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

输出:

__func__            f
__FUNCTION__        f
__PRETTY_FUNCTION__ static void N::C::f(int) [with T = char]
__PRETTY_FUNCTION__ static void N::C::f(double) [with T = void]

您可能还对带有函数名称的堆栈跟踪感兴趣:print call stack in C or C++

在 Ubuntu 19.04、GCC 8.3.0 中测试。

C++20std::source_location::function_name

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf进入了 C++20,所以我们还有另一种方法。

文档说:

constexpr const char* function_name() const noexcept;

6 返回:如果此对象表示函数体中的一个位置,则返回一个与函数名称对应的实现定义的 NTBS。否则,返回一个空字符串。

其中 NTBS 表示“空终止字节字符串”。

该功能存在于 GCC 11.2 Ubuntu 21.10 和-std=c++20. 它不在 GCC 9.1.0 上,带有g++-9 -std=c++2a.

https://en.cppreference.com/w/cpp/utility/source_location显示用法是:

主文件

#include <iostream>
#include <string_view>
#include <source_location>
 
void log(std::string_view message,
         const std::source_location& location = std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}
 
int main() {
    log("Hello world!");
}

编译并运行:

g++ -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

输出:

info:main.cpp:17:int main() Hello world!

所以请注意它如何返回调用者信息,因此非常适合用于日志记录,另请参阅:Is there a way to get function name inside a C++ function?

于 2015-07-01T14:14:10.803 回答
17

__func__记录在 C++0x 标准的第 8.4.1 节中。在这种情况下,它是一个预定义的函数局部变量,形式为:

static const char __func__[] = "function-name ";

其中“函数名称”是特定于实现的。这意味着每当您声明一个函数时,编译器都会将此变量隐式添加到您的函数中。__FUNCTION__和也是如此__PRETTY_FUNCTION__。尽管它们是大写的,但它们不是宏。虽然__func__是对 C++0x 的补充

g++ -std=c++98 ....

仍将使用__func__.

__PRETTY_FUNCTION____FUNCTION__记录在这里http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names__FUNCTION__只是__func__. __PRETTY_FUNCTION__与 C中的相同,__func__但在 C++ 中它也包含类型签名。

于 2010-12-08T06:44:50.347 回答
10

对于那些想知道它在 VS 中如何进行的人。

MSVC 2015 更新 1,cl.exe 版本 19.00.24215.1:

#include <iostream>

template<typename X, typename Y>
struct A
{
  template<typename Z>
  static void f()
  {
    std::cout << "from A::f():" << std::endl
      << __FUNCTION__ << std::endl
      << __func__ << std::endl
      << __FUNCSIG__ << std::endl;
  }
};

void main()
{
  std::cout << "from main():" << std::endl
    << __FUNCTION__ << std::endl
    << __func__ << std::endl
    << __FUNCSIG__ << std::endl << std::endl;

  A<int, float>::f<bool>();
}

输出:

从主():
主要的
主要的
int __cdecl main(void)

来自 A::f():
A<int,float>::f
F
void __cdecl A<int,float>::f<bool>(void)

正如预期的那样,使用__PRETTY_FUNCTION__触发器未声明的标识符错误。

于 2017-08-02T15:21:37.153 回答