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?
This question is related to
c++
debugging
logging
c-preprocessor
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.
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.
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.
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".
I'll give it a try when support arrives to GCC, GCC 9.1.0 with g++-9 -std=c++2a
still doesn't support it.
https://en.cppreference.com/w/cpp/utility/source_location claims usage will be like:
#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!");
}
Possible output:
info:main.cpp:16: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__?
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. */
}
Source: Stackoverflow.com