__PRETTY_FUNCTION__
、__FUNCTION__
、__func__
之间有什么区别,它们在哪里记录?我如何决定使用哪一个?
__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++ 编译器 "Predefined Macros" 的 MSDN 文档中。 gcc 文档扩展在 gcc 文档页面 "Function Names as Strings." 中进行了描述
尽管没有完全回答最初的问题,但这可能是大多数谷歌搜索的人想要看到的。
对于海湾合作委员会:
$ 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**)
__func__
嵌入到另一个函数中时它会起作用吗?假设我有function1,它不需要参数。 function1 调用包含 __func__
的 function2,将打印哪个函数名称,1 还是 2?
__func__
是一个宏,它将转换为您当前所在的任何函数。如果您将其放入 f1 并在 f2 中调用 f1,您将始终得到 f1。
__func__
是预定义的标识符,而不是宏。
__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++20 std::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 表示“空终止字节字符串”。
该功能存在于带有 -std=c++20
的 GCC 11.2 Ubuntu 21.10 上。它不在带有 g++-9 -std=c++2a
的 GCC 9.1.0 上。
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?
__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__
不是 C++03 的一部分。它已在 C++0x 中添加,但 C++0x 还不是“C++ 标准”,它仍处于草案形式。
对于那些想知道它在 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>();
}
输出:
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__
会触发未声明的标识符错误。
void main()
在技术上是错误的。 main
,但是根据参数定义必须返回 int
。
__FUNCTION__
,但它们做的事情略有不同。 gcc 给出__func__
的等价物。 VC 给出了未经修饰但仍然经过修饰的名称版本。对于名为“foo”的方法,gcc 会给出"foo"
,VC 会给出"my_namespace::my_class::foo"
。__PRETTY_FUNCTION__
时,它确实显示在列表中,当我将鼠标移到它上面时,它确实显示了有关函数名称的信息,但是它确实失败了编译。