__FILE __,__ LINE__和__FUNCTION__在C ++中的用法


158

假设您的C ++编译器支持它们,是否有任何特定的原因使用__FILE____LINE__以及__FUNCTION__出于日志记录和调试的目的?

我主要关心的是为用户提供误导性数据,例如,由于优化而报告错误的行号或功能,或者因此而导致性能下降。

基本上,我可以信任__FILE____LINE____FUNCTION__永远做正确的事?


LINE应该做正确的事。我已经广泛使用了它及其队列,包括PRETTY_FUNCTION。...但是...好吧,我现在正在查看LINE所在的代码。可能是因为它在try / catch异常处理的catch块中。
Krazy Glew,2012年

Answers:


191

__FUNCTION__是非标准的,__func__存在于C99 / C ++ 11中。其他(__LINE____FILE__)都很好。

它将始终报告正确的文件和行(如果选择使用__FUNCTION__/ ,则会报告功能__func__)。优化不是一个因素,因为它是编译时宏扩展。它绝不会以任何方式影响性能。


3
__func__在C ++中有点问题。C99没有说出默认参数之类的话,在不太明显的情况下,__func__C ++应该如何表现。
威廉希尔2012年

4
@thr:虽然您提出了一个要点。我很清楚,它__func__存在于c99中,而不是c ++中。无论如何,我认为使用__func__c ++ 进行合理的实现只会导致名称混乱。由于我不是编译器作家,所以这并不是我的真正要求。
埃文·特兰

哪些编译器根本不支持__FUNCTION__?除了最近的gcc之外,还有哪些编译器将其视为变量而不是宏?
2013年

36
__func__现在是C ++ 11标准。
VX

38

在极少数情况下,将给定的行更改为其他内容可能很有用__LINE__。我已经看到GNU configure会在一些原始行文件中未出现的行之间插入一些伏都教之后,对某些测试报告适当的行号。例如:

#line 100

将使以下几行以__LINE__100 开头。您可以选择添加新的文件名

#line 100 "file.c"

它很少有用。但是,如果有需要,我没有其他选择。实际上,代替行也可以使用宏,它必须导致上述两种形式中的任何一种。使用boost预处理程序库,您可以将当前行增加50:

#line BOOST_PP_ADD(__LINE__, 50)

我认为提及它很有用,因为您询问了__LINE__and 的用法__FILE__。人们永远不会从C ++中获得足够的惊喜:)

编辑: @Jonathan Leffler在评论中提供了一些更好的用例:

对于希望将用户C代码中报告的错误与用户源文件保持一致的预处理器,使用#line处理非常有用。Yacc,Lex和ESQL / C预处理器可以做到这一点。


29

仅供参考: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. */
}

2
很高兴了解__PRETTY_FUNCTION__。很有用!
郑区

8

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


29
“我可能将此信息记录到控制台”-或更妙的是:将其记录到文件中,以便在出现问题时可以要求客户将其发送给您...
Christoph

7

C ++ 20 std::source_location

C ++最终添加了一个非宏选项,当C ++ 20广泛使用时,它将在将来的某个时候占主导地位:

该文档说:

constexpr const char * function_name()const noexcept;

6返回:如果此对象表示函数主体中的位置,则返回应与函数名称对应的实现定义的NTBS。否则,返回一个空字符串。

其中NTBS表示“空终止字节字符串”。

当GCC支持到达时,我会尝试一下,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,
         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__vsstd::source_location::function_name

回答:__PRETTY_FUNCTION__,__FUNCTION__和__func__有什么区别?


1
<experimental/source_location>目前GCC-9。
陈浩南

5

我一直都在用它们。我唯一担心的是在日志文件中放弃IP。如果您的函数名称确实不错,那么您可能会更容易发现商业秘密。这有点像带有调试符号的运送方式,只是很难找到东西。在99.999%的情况下,不会有不好的结果。


1
提出来的好点。使用strings实用程序从可执行文件中提取所有类似于字符串的数据来提取此信息很简单。甚至可以提取压缩的可执行文件。请注意发送到客户站点的内容。通常,即使竞争对手不应该这样做,他们也可以使用您的可执行文件。
马蒂
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.