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

发布于 2024-07-14 20:27:28 字数 296 浏览 5 评论 0原文

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

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

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

Presuming that your C++ compiler supports them, is there any particular reason not to use __FILE__, __LINE__ and __FUNCTION__ for logging and debugging purposes?

I'm primarily concerned with giving the user misleading data—for example, reporting the incorrect line number or function as a result of optimization—or taking a performance hit as a result.

Basically, can I trust __FILE__, __LINE__ and __FUNCTION__ to always do the right thing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

垂暮老矣 2024-07-21 20:27:28

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

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

__FUNCTION__ is non standard, __func__ exists in C99 / C++11. The others (__LINE__ and __FILE__) are just fine.

It will always report the right file and line (and function if you choose to use __FUNCTION__/__func__). Optimization is a non-factor since it is a compile time macro expansion; it will never affect performance in any way.

瞳孔里扚悲伤 2024-07-21 20:27:28

在极少数情况下,将 __LINE__ 给出的行更改为其他内容可能会很有用。 我见过 GNU configure 在某些测试中这样做,在原始源文件中未出现的行之间插入一些巫术后报告适当的行号。 例如:

#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 预处理器就是这样做的。

In rare cases, it can be useful to change the line that is given by __LINE__ to something else. I've seen GNU configure does that for some tests to report appropriate line numbers after it inserted some voodoo between lines that do not appear in original source files. For example:

#line 100

Will make the following lines start with __LINE__ 100. You can optionally add a new file-name

#line 100 "file.c"

It's only rarely useful. But if it is needed, there are no alternatives I know of. Actually, instead of the line, a macro can be used too which must result in any of the above two forms. Using the boost preprocessor library, you can increment the current line by 50:

#line BOOST_PP_ADD(__LINE__, 50)

I thought it's useful to mention it since you asked about the usage of __LINE__ and __FILE__. One never gets enough surprises out of C++ :)

Edit: @Jonathan Leffler provides some more good use-cases in the comments:

Messing with #line is very useful for pre-processors that want to keep errors reported in the user's C code in line with the user's source file. Yacc, Lex, and (more at home to me) ESQL/C preprocessors do that.

一人独醉 2024-07-21 20:27:28

C++20 std::source_location

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

文档说:

constexpr const char* function_name() const noexcept;

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

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

该功能存在于带有 -std=c++20 的 GCC 11.2 Ubuntu 21.10 上。 它不在带有 g++-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,
         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__、__FUNCTION__、__func__ 之间有什么区别?

C++20 std::source_location

C++ has finally added a non-macro option, and it will likely dominate at some point in the future when C++20 becomes widespread:

The documentation says:

constexpr const char* function_name() const noexcept;

6 Returns: If this object represents a position in the body of a function,
returns an implementation-defined NTBS that should correspond to the
function name. Otherwise, returns an empty string.

where NTBS means "Null Terminated Byte String".

The feature is present on GCC 11.2 Ubuntu 21.10 with -std=c++20. It was not on GCC 9.1.0 with g++-9 -std=c++2a.

https://en.cppreference.com/w/cpp/utility/source_location shows usage is:

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!");
}

Compile and run:

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

Output:

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

__PRETTY_FUNCTION__ vs __FUNCTION__ vs __func__ vs std::source_location::function_name

Answered at: What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__?

述情 2024-07-21 20:27:28

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

FYI: g++ offers the non-standard __PRETTY_FUNCTION__ macro. Until just now I did not know about C99 __func__ (thanks Evan!). I think I still prefer __PRETTY_FUNCTION__ when it's available for the extra class scoping.

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. */
}
最终幸福 2024-07-21 20:27:28

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

Personally, I'm reluctant to use these for anything but debugging messages. I have done it, but I try not to show that kind of information to customers or end users. My customers are not engineers and are sometimes not computer savvy. I might log this info to the console, but, as I said, reluctantly except for debug builds or for internal tools. I suppose it does depend on the customer base you have, though.

迟到的我 2024-07-21 20:27:28

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

I use them all the time. The only thing I worry about is giving away IP in log files. If your function names are really good you might be making a trade secret easier to uncover. It's sort of like shipping with debug symbols, only more difficult to find things. In 99.999% of the cases nothing bad will come of it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文