假设你的C++编译器支持它们,有没有什么特殊的原因 * 不 * 使用__FILE__,__LINE__和__FUNCTION__来记录和调试?我主要关心的是给用户提供误导性的数据例如,报告不正确的行号或函数作为优化的结果,或者因此而导致性能下降。基本上,我能相信__FILE__、__LINE__和__FUNCTION__总是做正确的事情吗?
__FILE__
__LINE__
__FUNCTION__
qzlgjiam1#
__FUNCTION__是非标准的,__func__存在于C99 / C++11中。其他的(__LINE__和__FILE__)都很好。它总是报告正确的文件和行(如果你选择使用__FUNCTION__/__func__,还有函数)。优化是一个无关紧要的因素,因为它是一个编译时宏扩展;它将永远以任何方式影响性能。
__func__
kqhtkvqz2#
在极少数情况下,将__LINE__给出的行更改为其他行可能很有用。我见过GNU configure在一些测试中这样做,以便在原始源文件中没有出现的行之间插入一些voodoo之后报告适当的行号。例如:
#line 100
字符串将使以下行以__LINE__ 100开头。您可以选择添加新的文件名
#line 100 "file.c"
型它很少有用。但如果需要,我知道没有替代方案。实际上,除了这一行,也可以使用宏,它必须导致上述两种形式中的任何一种。使用boost预处理器库,您可以将当前行增加50:
#line BOOST_PP_ADD(__LINE__, 50)
型我认为提到它是有用的,因为你问了__LINE__和__FILE__的用法。人们从C++中永远不会得到足够的惊喜:)
编辑:@Jonathan Leffler在评论中提供了一些更好的用例:
如果预处理器想让用户的C代码中报告的错误与用户的源文件保持一致,那么使用#line非常有用。Yacc、Lex和(对我来说更熟悉的)ESQL/C预处理器可以做到这一点。
lsmd5eda3#
C++20 std::source_location
std::source_location
C终于增加了一个非宏选项,当C20变得广泛时,它可能会在未来的某个时候占据主导地位:
该文件说: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显示的用法是:main.cpp
-std=c++20
g++-9 -std=c++2a
#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__
std::source_location::function_name
解析:PRETTY_FUNCTION、FUNCTION、__func__之间有什么区别?
a1o7rhls4#
FYI:g++提供了非标准的__PRETTY_FUNCTION__宏。直到刚才我还不知道C99 func(谢谢Evan!)。我想我还是更喜欢__PRETTY_FUNCTION__,当它可用于额外的类作用域时。附言:
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. */ }
字符串
lvmkulzt5#
就我个人而言,除了调试消息之外,我不太愿意使用这些信息。我已经这样做了,但我尽量不向客户或最终用户显示这类信息。我的客户不是工程师,有时也不懂计算机。我可能会将这些信息记录到控制台,但正如我所说,除了调试版本或内部工具之外,我不太愿意。不过,我想这确实取决于你的客户群。
voj3qocg6#
我一直在使用它们。我唯一担心的是在日志文件中泄露IP。如果你的函数名真的很好,你可能会使商业秘密更容易被发现。这有点像与调试符号一起发布,只是更难找到东西。在99.999%的情况下,不会有什么不好的结果。
6条答案
按热度按时间qzlgjiam1#
__FUNCTION__
是非标准的,__func__
存在于C99 / C++11中。其他的(__LINE__
和__FILE__
)都很好。它总是报告正确的文件和行(如果你选择使用
__FUNCTION__
/__func__
,还有函数)。优化是一个无关紧要的因素,因为它是一个编译时宏扩展;它将永远以任何方式影响性能。kqhtkvqz2#
在极少数情况下,将
__LINE__
给出的行更改为其他行可能很有用。我见过GNU configure在一些测试中这样做,以便在原始源文件中没有出现的行之间插入一些voodoo之后报告适当的行号。例如:字符串
将使以下行以
__LINE__
100开头。您可以选择添加新的文件名型
它很少有用。但如果需要,我知道没有替代方案。实际上,除了这一行,也可以使用宏,它必须导致上述两种形式中的任何一种。使用boost预处理器库,您可以将当前行增加50:
型
我认为提到它是有用的,因为你问了
__LINE__
和__FILE__
的用法。人们从C++中永远不会得到足够的惊喜:)编辑:@Jonathan Leffler在评论中提供了一些更好的用例:
如果预处理器想让用户的C代码中报告的错误与用户的源文件保持一致,那么使用#line非常有用。Yacc、Lex和(对我来说更熟悉的)ESQL/C预处理器可以做到这一点。
lsmd5eda3#
C++20
std::source_location
C终于增加了一个非宏选项,当C20变得广泛时,它可能会在未来的某个时候占据主导地位:
该文件说:
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显示的用法是:
main.cpp
字符串
编译并运行:
型
输出量:
型
__PRETTY_FUNCTION__
vs__FUNCTION__
vs__func__
vsstd::source_location::function_name
解析:PRETTY_FUNCTION、FUNCTION、__func__之间有什么区别?
a1o7rhls4#
FYI:g++提供了非标准的__PRETTY_FUNCTION__宏。直到刚才我还不知道C99 func(谢谢Evan!)。我想我还是更喜欢__PRETTY_FUNCTION__,当它可用于额外的类作用域时。
附言:
字符串
lvmkulzt5#
就我个人而言,除了调试消息之外,我不太愿意使用这些信息。我已经这样做了,但我尽量不向客户或最终用户显示这类信息。我的客户不是工程师,有时也不懂计算机。我可能会将这些信息记录到控制台,但正如我所说,除了调试版本或内部工具之外,我不太愿意。不过,我想这确实取决于你的客户群。
voj3qocg6#
我一直在使用它们。我唯一担心的是在日志文件中泄露IP。如果你的函数名真的很好,你可能会使商业秘密更容易被发现。这有点像与调试符号一起发布,只是更难找到东西。在99.999%的情况下,不会有什么不好的结果。