181

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

我主要关心的是向用户提供误导性数据——例如,报告错误的行号或函数作为优化的结果——或者因此导致性能下降。

__FILE__基本上,我可以信任__LINE__始终__FUNCTION__做正确的事吗?

4

6 回答 6

214

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

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

于 2009-02-27T23:28:58.787 回答
39

在极少数情况下,将给出的行更改为其他内容可能很有用__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 预处理器就是这样做的。

于 2009-02-27T23:59:48.150 回答
32

仅供参考: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. */
}
于 2009-02-28T13:37:40.070 回答
19

C++20std::source_location

C++ 终于添加了一个非宏选项,当 C++20 普及时,它可能会在未来某个时候占据主导地位:

文档说:

constexpr const char* function_name() const noexcept;

6 返回:如果此对象表示函数体中的一个位置,则返回一个实现定义的 NTBS,该 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,
         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!");
}

编译并运行:

g++ -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

输出:

info:main.cpp:17:int main() Hello world!

__PRETTY_FUNCTION____FUNCTION____func__std::source_location::function_name

回答于:__PRETTY_FUNCTION__、__FUNCTION__、__func__ 有什么区别?

于 2020-01-15T09:04:19.750 回答
8

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

于 2009-02-27T23:30:38.267 回答
4

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

于 2015-02-05T05:36:27.373 回答