C++ Concatenating _File_ and _Line_ MACros

C++ concatenating __FILE__ and __LINE__ macros?

You need to expand that macro in two levels:

#define S1(x) #x
#define S2(x) S1(x)
#define LOCATION __FILE__ " : " S2(__LINE__)

Here is the reason:

You need expand __LINE__ in two levels, before passing it to #x.

First of all, using operator # in a function-like macro, it has to be followed by a macro parameter but __LINE__ is not a parameter, so compiler complains it's a stray operator.

On the other hand, __LINE__ itself is a macro and contains current line number, it should be expanded to the number before using it with #, otherwise, you will get string "__LINE__" instead of a number.

Macro S2(__LINE__) expands __LINE__ to a line number, then we pass the line number to #x.

How to concat __func__ and __LINE__ in a macro definition

gives a compilation error [...] anyone know the reason for this

__func__ is a variable:

static const char __func__[] = "function-name";

It is not to a (string) literal (to which for example __FILE__ "expands".)

(docs are here: https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html)

Creating C macro with ## and __LINE__ (token concatenation with positioning macro)

The problem is that when you have a macro replacement, the preprocessor will only expand the macros recursively if neither the stringizing operator # nor the token-pasting operator ## are applied to it. So, you have to use some extra layers of indirection, you can use the token-pasting operator with a recursively expanded argument:

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}

Then, __LINE__ gets expanded to the line number during the expansion of UNIQUE (since it's not involved with either # or ##), and then the token pasting happens during the expansion of TOKENPASTE.

It should also be noted that there is also the __COUNTER__ macro, which expands to a new integer each time it is evaluated, in case you need to have multiple instantiations of the UNIQUE macro on the same line. Note: __COUNTER__ is supported by MS Visual Studio, GCC (since V4.3), and Clang, but is not standard C.

How to get filename from __FILE__ and concat with __LINE__ at compile time

For your specific case (getting the filename without path and the line number) there are a few easier approaches that you might want to use:



1. Using __FILE_NAME__ instead of __FILE__

Both gcc and clang support the __FILE_NAME__ macro, that just resolves to the filename instead of the full file path.

  • clang builtin macros
  • gcc common macros

Utilizing those you can write it as a single macro:


#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STRINGIFY_IMPL(x) #x

#define FILENAME __FILE_NAME__ ":" STRINGIFY(__LINE__)

// Usage:
constexpr char* foo = FILENAME;
std::cout << foo << std::endl;

msvc unfortunately doesn't offer the __FILE_NAME__ macro, but you could utilize the /FC compiler switch to specify if you want the full path for __FILE__ or just the filename.

--

2. Let the compiler do the string concatenation

Adjacent character sequences are automatically combined by the compiler - e.g. "a" "b" "c" would be combined into "abc".

You can use this to let the compiler do the concatenation for you.

After that we can just increment the pointer to that combined string past the last slash to trim off the path:

#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STRINGIFY_IMPL(x) #x
#define FILENAME __FILE__ ":" STRINGIFY(__LINE__)

constexpr const char* filename_without_path(const char* path) {
const char* result = path;
while(*path != '\0')
if(*path++ == '/') result = path;

return result;
}

// Usage:
constexpr const char* foo = filename_without_path(FILENAME);
std::cout << foo << std::endl;


Why can't a string literal be concatenated to __FUNCTION__?

Isn't __FUNCTION__ a string literal?

No.

From https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Function-Names.html

These identifiers are variables, not preprocessor macros, and may not be used to initialize char arrays or be concatenated with string literals.



Related Topics



Leave a reply



Submit