How can I get __LINE__ as a string constant? [duplicate] - c++

This question already has answers here:
Convert a preprocessor token to a string
(6 answers)
Closed last year.
In C++ (or C) how can I get the line number (__LINE__) as a string?
In particular, I want a macro that magically has "example.cpp:14" on line 14 of example.cpp. C++ automatically combines juxtaposed string literals, so I just need __LINE__ as a string.

The trick to turning numerical constants into strings is the STR and XSTR macros, defined below:
#include <iostream>
//! See https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
#define XSTR(a) STR(a)
#define STR(a) #a
#define LINE_AS_STR XSTR(__LINE__)
#define FILE_AND_LINE __FILE__ ":" LINE_AS_STR
int main() {
constexpr const char* line = LINE_AS_STR;
std::cout << "That was line \"" << line << "\"" << std::endl;
std::cout << FILE_AND_LINE << std::endl;
}
output:
That was line "11"
example.cpp:13
https://godbolt.org/z/xzE1nWeMd

Related

Hashtag symbol in C++ macro expression [duplicate]

This question already has answers here:
What is the # for when formatting using %s
(7 answers)
Closed 2 years ago.
In the macro definition below, what does '#' symbol do? What is this syntax (#x) here?
#define print(x) cout<<(#x)<<" : "<<x<<endl;
# is the stringify operator. It turns the macro argument x into a string literal.
I can see no reason for the extra parens, #define print(x) cout << #x <<" : " << x << endl; would work just as well. Even better would be #define print(x) cout << #x <<" : " << (x) << endl; because the second use of x might require parens to be parsed correctly.

Preprocessing string concatenation

I would like to concatenate the 3 following strings to produce a good debug output, by using std::setw() after.
__ FILENAME__ , ":" and LINE
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define AT __FILENAME__ ":" __LINE__
#ifdef DEBUG
#ifdef VERBOSE
#define printDebug(x) std::cout << AT << x << std::flush
#else
#define printDebug(x) std::cout << x << std::flush
#endif
#else
#define printDebug(x)
#endif
But actually I receive errors saying that a ";" field is missing before ":". Does someone have an idea ?
I actually call the printDebug() function like that :
printDebug("[SUCCESS] Receiving Message");
You can concatenate string literals by putting them alongside each other.
":" is a string literal.
__LINE__ expands to a numeric literal, not string one.
__FILENAME__ doesn't expand to a literal at all. It expands to an expression.
There is a way to get a string literal out of __LINE__, but you can't make __FILENAME__ a string literal.
You don't need to use literal concatenation here at all. You can simply do this:
#ifdef VERBOSE
#define printDebug(x) std::cout << __FILENAME__ << ":" << __LINE__ << x << std::flush

preventing unexpected macro re-expansion with boost? [duplicate]

This question already has answers here:
How do I temporarily disable a macro expansion in C/C++?
(6 answers)
Closed 5 years ago.
The goal here is to simply get a, b, c out instead of their actual values. The setup is "simple enough":
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <iostream>
// Define "invalid" sequence first
#define SEQ (a)(b)(c)
// Try to create "final" value with `std::string("elem")`
// Brought in for explicit `std::string`, but no dice
#define MAKE_XSTRING(x) MAKE_STRING(x)
#define MAKE_STRING(x) std::string(#x)
// oh, the humanity! vvvvvvvvvvvv or BOOST_PP_STRINGIZE
#define HUMANIZE(r, data, elem) (MAKE_XSTRING(elem))
#define SEQ_HUMAN BOOST_PP_SEQ_FOR_EACH(HUMANIZE,,SEQ)
So what I'm expecting at this point is what I have: a new sequence with (std::string("a")) etc:
// confirmation: vvvvvvvvvvvvvvvv
// warning: Humans: (std::string("a")) (std::string("b")) (std::string("c"))
#pragma message "Humans: " BOOST_PP_STRINGIZE(SEQ_HUMAN)
Thinking I'm so very clever and have gotten my values sorted out in some explicit strings, now I define the actual values for what the "real" code needs.
// Now that we have the "final" values, actually define the real values
// in real code, it's some lengthy nested namespaces (inconvenient to type)
#define a 123
#define b 456
#define c 789
And at long last, lets print them to make sure they aren't expanded:
// Let there be printing!
#define GOTTA_PRINT_EM_ALL(r,data,i,elem) << ((i)+1) << ". " << elem << std::endl
int main(int argc, const char **argv) {
std::cout << "Humans: " << std::endl
BOOST_PP_SEQ_FOR_EACH_I(GOTTA_PRINT_EM_ALL,,SEQ_HUMAN);
}
But it seems the aliens did indeed take over:
Humans:
1. 123
2. 456
3. 789
Given that they're supposed to be std::string("a")...how the heck are the real values getting back in there?! I thought maybe the ("a") from the std::string constructor was creating issues, but it doesn't seem so (BOOST_PP_STRINGIZE results in same behavior). Any suggestions?
The macro indeed expands into code tokens:
test.cpp|24 col 1| note: #pragma message: Humans: (std::string("123")) (std::string("456")) (std::string("789"))
Now when you insert the code tokens into your GOTTA_PRINT_EM_ALL macro, you get
<< ((0)+1) << ". " << std::string(\"123\") << std::endl << ((1)+1) << ". " << std::string(\"456\") << std::endl << ((2)+1) << ". << std::string(\"789\")" << std::endl
Completely expectedly printing
Humans:
1. 123
2. 456
3. 789
To get the "code tokens" you need to stringize them as well:
// Let there be printing!
#define GOTTA_PRINT_EM_ALL(r,data,i,elem) << ((i)+1) << ". " << BOOST_PP_STRINGIZE(elem) << std::endl
Printing
Humans:
1. std::string("123")
2. std::string("456")
3. std::string("789")
See it Live On Coliru
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <iostream>
#include <string>
#define a 123
#define b 456
#define c 789
#define SEQ (a)(b)(c)
// Try to create "final" value with `std::string("elem")`
// Brought in for explicit `std::string`, but no dice
#define MAKE_STRING(x) std::string(#x)
#define MAKE_XSTRING(x) MAKE_STRING(x)
#define HUMANIZE(r, data, elem) (MAKE_XSTRING(elem))
#define SEQ_HUMAN BOOST_PP_SEQ_FOR_EACH(HUMANIZE,,SEQ)
// Let there be printing!
#define GOTTA_PRINT_EM_ALL(r,data,i,elem) << ((i)+1) << ". " << BOOST_PP_STRINGIZE(elem) << std::endl
int main() {
std::cout << "Humans: " << std::endl
BOOST_PP_SEQ_FOR_EACH_I(GOTTA_PRINT_EM_ALL,,SEQ_HUMAN);
}

VC++ marco, getting raw text of parameter

How do I get the text of the data given to value, not the value of the executed expression?
#define PRINT_VALUE(value) std::cout << "Value " << __RAWTEXT(value) << " is " << value << "\n";
__RAWTEXT is something I made up. Is there really something out there that does this though?
int testVariable = 5;
PRINT_VALUE(testVariable);
The output of this should be
Value testVariable is 5
Use the "stringize" operator # for this:
#define PRINT_VALUE(value) std::cout << "Value " << #value << " is " << value << "\n";
It's pretty straightforward, #TTT in a macro converts TTT to "TTT", a string literal.
It's worth mentioning that when the parameter is itself a macro, you'll get the name of the macro. However, if the parameter is passed to a subsequent macro, it's "unpacked". So you see these sometimes:
#define STRINGIZE2(X) #X
#define STRINGIZE(X) STRINGIZE2(X)
Here they are in action:
#define TEST Bob
std::cout << #TEST; //results in "TEST"
std::cout << STRINGIZE2(TEST); //results in "TEST"
std::cout << STRINGIZE(TEST); //results in "Bob"
Not relevent to your question but also notable is the "concat" macro operator ## which "glues" two bits of text togeather. std::st ## ing results in std::string. Useful in macros:
#define make_thing(X) \
structX##_class {
static const char* const name=#X;
};
make_thing(Foo);
std::cout << Foo_class::name;
And again, if a parameter is a macro, you get the macro name. So here's the de-macro macros:
#define GLUE2(X,Y) (X##Y)
#define GLUE(X,Y) GLUE2(X,Y)
#define HEY "HELLO"
#define THERE "WORLD"
std::cout << GLUE(HEY,THERE); //"HELLOWORLD"

Trouble creating assert function

This is my assert function (it wont compile "error C2110: '+' : cannot add two pointers"):
#define CHAR(x) #x
template<typename T>
inline void ASSERT(T x)
{
if(!x)
{
std::string s("ERROR! Assert " + CHAR(x) + " failed. In file " + __FILE__ +
" at line " + __LINE__ + ".");
std::wstring temp(s.length(), L' ');
std::copy(s.begin(), s.end(), temp.begin());
getLogger().Write(temp);
}
}
Any idea of how to fix it?
String Literals are easily reduced to char pointers, which cannot be added as you try to do with "ERROR! Assert " + CHAR(x) + " failed. In file ".... However, C++ has the handy feature of doing this automatically before compilation! (the preprocessor does this). Even better, it has a handy tool for making wide strings at compile time. So, you want:
#define _T(x) L ## x
#define CHAR(x) #x
#define CHAR2(x) CHAR(x)
#define ASSERT(x) ASSERT2(x, CHAR(x), __FILE__, CHAR2(__LINE__))
#define ASSERT2(x, t, f, l) \
if(!x) \
getLogger().Write(L"ERROR! Assert " _T(t) L" failed. In file " _T(f) L" at line " _T(l) L".");
http://ideone.com/0ibcj
The compiler error is quite clear; you are trying to apply the + operator to string literals. A quick way to fix it is enclosing the first string literal in std::string().
As #James McNellis pointed out, note that FILE and LINE will point to the file and line of the assert function declaration.
You cannot use the + operator to concatenate two char*s; you need printf or some sort of thing for that.
"ERROR! Assert " is a null-terminated, C-style string. You can't execute operator+ on it.
A few issues:
Generally an assert should break into the debugger or dump if one is not attached. This will not.
As already mentioned, your LINE and FILE require use in a macro
You need a couple "helper" macros to get the strings working properly
Try something along these lines:
#define ASSERT_QUOTE_(x) #x
#define ASSERT_QUOTE_(x) ASSERT_QUOTE_(x)
#define MY_ASSERT(cond) \
if(cond) {} else { \
std::stringstream ss; \
ss << "ERROR! Assert " << ASSERT_QUOTE(cond) << " failed. In file " << __FILE__ << " at line " << __LINE__ << "."; \
getLogger().Write(ss.str()); \
}
Be careful trying to use STL here however. I suggest you have your logger's Write() function take variable arguments and process them with printf() or perhaps boost::format