假设您的C ++编译器支持它们,是否有任何特殊原因 使用__FILE__
,__LINE__
和__FUNCTION__
进行日志记录和调试?< / p>
我主要关注的是为用户提供误导性数据 - 例如,由于优化而报告错误的行号或功能,或者因此导致性能下降。
基本上,我可以信任__FILE__
,__LINE__
和__FUNCTION__
总是做正确的事吗?
答案 0 :(得分:169)
__FUNCTION__
是非标准的,C99 / C ++ 11中存在__func__
。其他人(__LINE__
和__FILE__
)也没关系。
它将始终报告正确的文件和行(如果您选择使用__FUNCTION__
/ __func__
,则会显示功能)。优化是一个非因素,因为它是一个编译时宏扩展; 永远不会以任何方式影响效果。
答案 1 :(得分:36)
在极少数情况下,将__LINE__
给出的行更改为其他内容会很有用。我已经看到GNU configure为某些测试报告了适当的行号,它在原始源文件中没有出现的行之间插入了一些伏都教。例如:
#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预处理器就是这样做的。
答案 2 :(得分:28)
仅供参考:g ++提供非标准的__PRETTY_FUNCTION__宏。直到现在我还不知道C99 __func__(谢谢Evan!)。我认为当它可用于额外的类范围时,我仍然更喜欢__PRETTY_FUNCTION__。
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. */
}
答案 3 :(得分:8)
C ++ 20 std::source_location
C ++最终添加了一个非宏选项,当C ++ 20广泛使用时,它将在将来的某个时候占主导地位。
文档说:
constexpr const char * function_name()const noexcept;
6返回:如果此对象表示函数主体中的位置, 返回实现定义的NTBS,该NTBS应该与 函数名称。否则,返回一个空字符串。
其中NTBS表示“空终止字节字符串”。
当支持到达GCC时,我会尝试一下,带有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!");
}
可能的输出:
info:main.cpp:16:main Hello world!
__PRETTY_FUNCTION__
vs __FUNCTION__
vs __func__
vs std::source_location::function_name
回答于:What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__?
答案 4 :(得分:7)
就个人而言,除了调试消息之外,我不愿意使用它们。我已经做到了,但我尽量不向客户或最终用户展示这类信息。我的客户不是工程师,有时不精通计算机。我可能会将此信息记录到控制台,但正如我所说,除了调试版本或内部工具之外,我不情愿。不过,我认为这取决于您拥有的客户群。
答案 5 :(得分:5)
我一直都在使用它们。我唯一担心的是在日志文件中赠送IP。如果你的功能名称非常好,你可能会更容易发现商业机密。这有点像带有调试符号的运输,只有更难找到的东西。在99.999%的情况下,没有什么不好的。