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

Posted

技术标签:

【中文标题】__FILE__、__LINE__ 和 __FUNCTION__ 在 C++ 中的用法【英文标题】:__FILE__, __LINE__, and __FUNCTION__ usage in C++ 【发布时间】:2010-10-10 11:18:26 【问题描述】:

假设您的 C++ 编译器支持它们,是否有任何特殊原因使用 __FILE____LINE____FUNCTION__ 进行日志记录和调试?

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

基本上,我可以相信__FILE____LINE____FUNCTION__ 能够始终做正确的事吗?

【问题讨论】:

LINE 应该做正确的事。我已广泛使用它及其同类群组,包括 PRETTY_FUNCTION。 ...但是...好吧,我现在正在查看 LINE 所在的代码。可能是因为它位于 try/catch 异常处理的 catch 块中。 相关:gcc reference for predefined macros 【参考方案1】:

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

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

【讨论】:

__func__ 是 C++ 中的一个问题。 C99 没有提及默认参数等,在某些情况下 __func__ 在 C++ 中的行为方式并不那么明显。 @thr:虽然你说得很好。我很清楚 __func__ 存在于 c99 中,而不是 c++ 中。无论如何,我认为在 c++ 中合理实现 __func__ 只会导致名称混乱。因为我不是编译器作者,所以这不是我的决定。 哪些编译器根本不支持__FUNCTION__?除了最近的 gcc 之外,还有哪些编译器将其视为变量而不是宏? __func__ 现在是 C++11 标准。 人们不禁想知道为什么他们选择不将其称为__FUNC__,以保持一致,或者为什么他们不只是将__FUNCTION__添加到C++11标准中而不是@ 987654335@【参考方案2】:

在极少数情况下,将__LINE__ 给出的行更改为其他内容会很有用。我已经看到 GNU configure 这样做是为了在一些测试中报告适当的行号,因为它在原始源文件中没有出现的行之间插入了一些巫术。例如:

#line 100

将使以下行以__LINE__ 100 开头。您可以选择添加新文件名

#line 100 "file.c"

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

#line BOOST_PP_ADD(__LINE__, 50)

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

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

#line 混淆对于希望将用户 C 代码中报告的错误与用户源文件保持一致的预处理器非常有用。 Yacc、Lex 和(对我来说更熟悉的)ESQL/C 预处理器可以做到这一点。

【讨论】:

【参考方案3】:

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

【讨论】:

很高兴了解 __PRETTY_FUNCTION__。很有用!【参考方案4】:

C++20 std::source_location

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

https://en.cppreference.com/w/cpp/utility/source_location http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1208r5.pdf

文档说:

constexpr const char* function_name() const noexcept;

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

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

该功能存在于 GCC 11.2 Ubuntu 21.10 上,-std=c++20g++-9 -std=c++2a 不在 GCC 9.1.0 上。

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,
         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__ vs __FUNCTION__ vs __func__ vs std::source_location::function_name

回复于:What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__?

【讨论】:

当前 gcc-9 中有&lt;experimental/source_location&gt;【参考方案5】:

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

【讨论】:

“我可能会将此信息记录到控制台” - 或者更好的是:将其记录到文件中,这样如果出现问题,您可以要求客户将其发送给您... @Christoph ...不要忘记定期缩小、删除或覆盖此类文件。否则,客户可能会想知道为什么她/他的磁盘有一天是满的...... :-)【参考方案6】:

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

【讨论】:

提出来的好点。使用strings 实用程序从可执行文件中提取所有类似字符串的数据来提取此信息很简单。甚至可以提取压缩的可执行文件。非常注意您发送到客户站点的内容。很多时候,竞争对手能够获得您的可执行文件,即使他们不应该这样做。 constexpr 可以使用查找表或按位 XOR 等来混淆二进制文件中的任何字符串文字。如果你搜索,那里有各种各样的例子。当然,混淆只是混淆而不是安全,但如果您不想让您的文件和功能在二进制文件中显而易见,这是一种选择。

以上是关于__FILE__、__LINE__ 和 __FUNCTION__ 在 C++ 中的用法的主要内容,如果未能解决你的问题,请参考以下文章

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

在不使用 #define 的情况下捕获 __LINE__ 和 __FILE__

如何让__FILE __,__ func__和__LINE__宏在单行中工作?

__LINE__ __FILE__ 或 qml 中的类似函数

C++中的三个特殊宏:__FILE__,__FUNCTION__和__LINE__

__FILE__,__LINE__