假设您的 C++ 编译器支持它们,是否有任何特殊原因不使用
__FILE__
、__LINE__
和 __FUNCTION__
进行日志记录和调试?
我主要关心的是向用户提供误导性数据,例如,由于优化而报告错误的行号或函数,或者导致性能下降。
基本上,我可以相信
__FILE__
、__LINE__
和__FUNCTION__
会永远做正确的事吗?
__FUNCTION__
是非标准的,__func__
存在于 C99 / C++11 中。其他(__LINE__
和__FILE__
)都很好。
它将始终报告正确的文件和行(如果您选择使用
__FUNCTION__
/__func__
,则可以运行)。优化不是一个因素,因为它是编译时宏扩展;它永远不会以任何方式影响性能。
__LINE__
给出的行更改为其他内容可能会很有用。我见过 GNU 配置 在某些测试中这样做,在原始源文件中未出现的行之间插入一些巫术后报告适当的行号。例如:
#line 100
将使以下行以
__LINE__
100 开头。您可以选择添加新文件名
#line 100 "file.c"
它很少有用。但如果需要的话,据我所知没有其他选择。实际上,也可以使用宏来代替行,它必须导致上述两种形式中的任何一种。使用 boost 预处理器库,您可以将当前行增加 50:
#line BOOST_PP_ADD(__LINE__, 50)
我认为提及它很有用,因为您询问了
__LINE__
和
__FILE__
的用法。人们永远不会从 C++ 中获得足够的惊喜:)编辑:
@Jonathan Leffler 在评论中提供了一些更好的用例:
使用 #line 对于希望使用户 C 代码中报告的错误与用户源文件保持一致的预处理器非常有用。 Yacc、Lex 和(对我来说更熟悉)ESQL/C 预处理器就是这样做的。std::source_location
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,
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!
__PRETTY_FUNCTION__
vs
__FUNCTION__
vs __func__
vs std::source_location::function_name
回答于:__PRETTY_FUNCTION__、__FUNCTION__、__func__ 有什么区别?
PS:
static string getScopedClassMethod( string thePrettyFunction )
{
size_t index = thePrettyFunction . find( "(" );
if ( index == string::npos )
return thePrettyFunction; /* Degenerate case */
thePrettyFunction . erase( index );
index = thePrettyFunction . rfind( " " );
if ( index == string::npos )
return thePrettyFunction; /* Degenerate case */
thePrettyFunction . erase( 0, index + 1 );
return thePrettyFunction; /* The scoped class name. */
}