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
C++11 Type Trait to Differentiate Between Enum Class and Regular Enum
Serialize and Send a Data Structure Using Boost
In the Standard, What Is "Derived-Declarator-Type"
Is Is a Good Practice to Put the Definition of C++ Classes into the Header File
Where Does One Get the "Sys/Socket.H" Header/Source File
Counting the Number of Lines in a Text File
C++ Linking Error After Upgrading to MAC Os X 10.9/Xcode 5.0.1
How to Write the Following as a C++ MACro
Why Is Std::Vector::Operator[] 5 to 10 Times Faster Than Std::Vector::At()
Dead Code Identification (C++)
Window C/C++ Crypto API Examples and Tips
Opencv Grouprectangles - Getting Grouped and Ungrouped Rectangles
What's the Difference Between Span and Array_View in the Gsl Library
Specification of Source Charset Encoding in Msvc++, Like Gcc "-Finput-Charset=Charset"
Authenticating Users Using Active Directory in Client-Server Application
One Way of Eliminating C4251 Warning When Using Stl-Classes in the Dll-Interface