__PRETTY_FUNCTION__、__FUNCTION__、__func__ 之间有什么区别?

发布于 2024-10-06 13:20:41 字数 116 浏览 9 评论 0原文

__PRETTY_FUNCTION____FUNCTION____func__ 之间有什么区别,它们的记录在哪里?我如何决定使用哪一个?

What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__, and where are they documented? How do I decide which one to use?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

悟红尘 2024-10-13 13:20:41

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

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

static const char __func__[] = "函数名";

出现,其中 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__,并且仅在使用不支持它的编译器(例如,Visual C++,它不支持该功能)时才使用 __FUNCTION__支持C99,尚不支持所有C++0x,不提供__func__)。

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

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

__func__ is an implicitly declared identifier that expands to a character array variable containing the function name when it is used inside of a function. It was added to C in C99. From C99 §6.4.2.2/1:

The identifier __func__ is implicitly declared by the translator as if, immediately following the opening brace of each function definition, the declaration

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

appeared, where function-name is the name of the lexically-enclosing function. This name is the unadorned name of the function.

Note that it is not a macro and it has no special meaning during preprocessing.

__func__ was added to C++ in C++11, where it is specified as containing "an implementation-defined string" (C++11 §8.4.1[dcl.fct.def.general]/8), which is not quite as useful as the specification in C. (The original proposal to add __func__ to C++ was N1642).

__FUNCTION__ is a pre-standard extension that some C compilers support (including gcc and Visual C++); in general, you should use __func__ where it is supported and only use __FUNCTION__ if you are using a compiler that does not support it (for example, Visual C++, which does not support C99 and does not yet support all of C++0x, does not provide __func__).

__PRETTY_FUNCTION__ is a gcc extension that is mostly the same as __FUNCTION__, except that for C++ functions it contains the "pretty" name of the function including the signature of the function. Visual C++ has a similar (but not quite identical) extension, __FUNCSIG__.

For the nonstandard macros, you will want to consult your compiler's documentation. The Visual C++ extensions are included in the MSDN documentation of the C++ compiler's "Predefined Macros". The gcc documentation extensions are described in the gcc documentation page "Function Names as Strings."

秋心╮凉 2024-10-13 13:20:41

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

对于海湾合作委员会:

$ 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**)

Despite not fully answering the original question, this is probably what most people googling this wanted to see.

For GCC:

$ 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**)
莳間冲淡了誓言ζ 2024-10-13 13:20:41

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

main.cpp

#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]

您可能还对带有函数名称的堆栈跟踪感兴趣:如何在调用某个函数时打印堆栈跟踪

已测试在 Ubuntu 19.04、GCC 8.3.0 中。

C++20 std::source_location::function_name

main.cpp

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         std::source_location location = std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int f(int i) {
    log("Hello world!"); // Line 16
    return i + 1;
}

int f(double i) {
    log("Hello world!"); // Line 21
    return i + 1.0;
}

int main() {
    f(1);
    f(1.0);
}

编译并运行:

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

输出:

info:source_location.cpp:16:int f(int) Hello world!
info:source_location.cpp:21:int f(double) Hello world!

因此请注意它如何返回调用者信息,因此非常适合在日志记录,另请参阅: 是有没有办法在 C++ 函数中获取函数名称?

提案:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

该文档说:

constexpr const char* function_name() const noexcept;

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

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

在 GCC 11.3 Ubuntu 22.04 上测试。它不在带有 g++-9 -std=c++2a 的 GCC 9.1.0 上。

__PRETTY_FUNCTION__ handles C++ features: classes, namespaces, templates and overload

main.cpp

#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);
}

Compile and run:

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

Output:

__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]

You may also be interested in stack traces with function names: How to print a stack trace whenever a certain function is called

Tested in Ubuntu 19.04, GCC 8.3.0.

C++20 std::source_location::function_name

main.cpp

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         std::source_location location = std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int f(int i) {
    log("Hello world!"); // Line 16
    return i + 1;
}

int f(double i) {
    log("Hello world!"); // Line 21
    return i + 1.0;
}

int main() {
    f(1);
    f(1.0);
}

Compile and run:

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

Output:

info:source_location.cpp:16:int f(int) Hello world!
info:source_location.cpp:21:int f(double) Hello world!

so note how this returns the caller information, and is therefore perfect for usage in logging, see also: Is there a way to get function name inside a C++ function?

The proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

The documentation says:

constexpr const char* function_name() const noexcept;

6 Returns: If this object represents a position in the body of a function,
returns an implementation-defined NTBS that should correspond to the
function name. Otherwise, returns an empty string.

where NTBS means "Null Terminated Byte String".

Tested on GCC 11.3 Ubuntu 22.04. It was not on GCC 9.1.0 with g++-9 -std=c++2a.

终难遇 2024-10-13 13:20:41

__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++ 中它也包含类型签名。

__func__ is documented in the C++0x standard at section 8.4.1. In this case it's a predefined function local variable of the form:

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

where "function name" is implementation specfic. This means that whenever you declare a function, the compiler will add this variable implicitly to your function. The same is true of __FUNCTION__ and __PRETTY_FUNCTION__. Despite their uppercasing, they aren't macros. Although __func__ is an addition to C++0x

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

will still compile code using __func__.

__PRETTY_FUNCTION__ and __FUNCTION__ are documented here http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Function-Names.html#Function-Names. __FUNCTION__ is just another name for __func__. __PRETTY_FUNCTION__ is the same as __func__ in C but in C++ it contains the type signature as well.

宣告ˉ结束 2024-10-13 13:20:41

对于那些想知道 VS 中的情况如何的人。

MSVC 2015 Update 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>();
}

输出:

from main():
main
main
int __cdecl main(void)

from A::f():
A<int,float>::f
f
void __cdecl A<int,float>::f<bool>(void)

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

For those, who wonder how it goes in VS.

MSVC 2015 Update 1, cl.exe version 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>();
}

output:

from main():
main
main
int __cdecl main(void)

from A::f():
A<int,float>::f
f
void __cdecl A<int,float>::f<bool>(void)

Using of __PRETTY_FUNCTION__ triggers undeclared identifier error, as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文