197

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?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Runcible
  • 7,006
  • 12
  • 42
  • 62
  • __LINE__ should do the right thing. I have used it and its cohorts extensively, including __PRETTY_FUNCTION__. ... But ... well, I am just right now looking at code where __LINE__ lies. Probably because it is in a catch block for try/catch exception handling. – Krazy Glew Oct 11 '12 at 05:08
  • 5
    relevant: [gcc reference for predefined macros](http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html) – Alexander Malakhov Nov 02 '12 at 08:43
  • You need a macro to develop `__LINE__` from the place where the logger is called, not from the logger itself. – Sandburg May 16 '22 at 13:57

6 Answers6

229

__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.

Qqwy
  • 5,214
  • 5
  • 42
  • 83
Evan Teran
  • 87,561
  • 32
  • 179
  • 238
  • 3
    `__func__` is kind of a problem in C++. C99 doesn't say a word about default arguments and so forth, cases where it's not so obvious how `__func__` should behave in C++. – wilhelmtell Jan 29 '12 at 03:17
  • 4
    @thr: while you make a good point. I was pretty clear that `__func__` exists in c99, not c++. Regardless, I think a reasonable implementation of `__func__` in c++ would just result in the mangled name. Since I'm not a compiler writer, it's not really my call. – Evan Teran Apr 05 '12 at 03:13
  • 1
    What compilers not support `__FUNCTION__` at all? What compilers except recent gcc treat this as a variable, not a macro? – basin Jan 18 '13 at 09:11
  • 41
    `__func__` is now in C++11 standard. – V-X Sep 25 '13 at 08:09
  • 4
    One cannot help but wonder why they chose not to shout it as `__FUNC__`, to be consistent, or why they didn't just add `__FUNCTION__` to the C++11 standard instead of `__func__` – bobobobo Oct 04 '21 at 19:21
  • Also, filenames could be UCS-2, which needs to get `__WFILE__` via `#define __WFILE__ WIDEN(__FILE__)` – Sandburg May 17 '22 at 07:28
  • @bobobobo Presumably this is to highlight the difference that unlike the others, `__func__` is not a macro, but more like an automatically defined variable ("predefined identifier" as the standard calls it) – PhilipRoman May 02 '23 at 06:50
39

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.

kvantour
  • 25,269
  • 4
  • 47
  • 72
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
32

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. */
}
Mr.Ree
  • 8,320
  • 27
  • 30
31

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

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__?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
7

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.

Craig S
  • 952
  • 4
  • 7
  • 31
    "I might log this info to the console" - or better yet: log it to a file so that if something goes wrong you can ask the customer to send it to you... – Christoph Feb 27 '09 at 23:54
  • 2
    @Christoph ...and don't forget to shrink, remove, or overwrite such file periodically. Otherwise, the customer might wonder why her/his disk is full one day... :-) – Scheff's Cat Oct 07 '21 at 08:41
4

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.

JeffCharter
  • 1,431
  • 17
  • 27
  • 1
    Good point to bring up. It is trivial to extract this information using the `strings` utility to extract all string-like data from the executable. Even compressed executables can be extracted. Be very mindful of what you send out to a customer site. Often times competitors are able to get their hands on your executables, even though they are not supposed to do so. – Marty Dec 14 '15 at 18:54
  • It's possible with constexpr that uses a lookup table or bitwise XOR, etc. to obfuscate any string literals in your binary. There are various examples out there if you search. Of course obfuscation is just obfuscation and not security, but if you don't want to make your files and functions obvious in the binary it's an option. – idij Jul 24 '20 at 16:09