C++中的__FILE__、__LINE__和__FUNCTION__用法

dffbzjpn  于 9个月前  发布在  其他
关注(0)|答案(6)|浏览(144)

假设你的C++编译器支持它们,有没有什么特殊的原因 * 不 * 使用__FILE____LINE____FUNCTION__来记录和调试?
我主要关心的是给用户提供误导性的数据例如,报告不正确的行号或函数作为优化的结果,或者因此而导致性能下降。
基本上,我能相信__FILE____LINE____FUNCTION__总是做正确的事情吗?

qzlgjiam

qzlgjiam1#

__FUNCTION__是非标准的,__func__存在于C99 / C++11中。其他的(__LINE____FILE__)都很好。
它总是报告正确的文件和行(如果你选择使用__FUNCTION__/__func__,还有函数)。优化是一个无关紧要的因素,因为它是一个编译时宏扩展;它将永远以任何方式影响性能。

kqhtkvqz

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预处理器可以做到这一点。

lsmd5eda

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

#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_FUNCTIONFUNCTION、__func__之间有什么区别?

a1o7rhls

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. */
}

字符串

lvmkulzt

lvmkulzt5#

就我个人而言,除了调试消息之外,我不太愿意使用这些信息。我已经这样做了,但我尽量不向客户或最终用户显示这类信息。我的客户不是工程师,有时也不懂计算机。我可能会将这些信息记录到控制台,但正如我所说,除了调试版本或内部工具之外,我不太愿意。不过,我想这确实取决于你的客户群。

voj3qocg

voj3qocg6#

我一直在使用它们。我唯一担心的是在日志文件中泄露IP。如果你的函数名真的很好,你可能会使商业秘密更容易被发现。这有点像与调试符号一起发布,只是更难找到东西。在99.999%的情况下,不会有什么不好的结果。

相关问题