How to get the definition of a macro as a string literal? - c++

Say in a header, which I do not want to read myself but which I do include, I have
#define A B
#define B C
Now
#define STR(name) # name
defines a macro that gives me the name of any macro as a string, and
#define EXP_STR(name) STR(name)
defines a macro that gives me the full expansion of any macro as a string. So
cout << STR(A) << EXP_STR(A) << endl;
will print AC.
Is there any way to get "B" from A using some macros?

Since you can write
#define B C
#define A B
#define STR(name) # name
#define EXP_STR(name) STR(name)
and the
cout << STR(A) << EXP_STR(A) << endl;
will output exaclty the same, it means that it's not possible.
When you do this
#define A B
and then
#define B C
now this means that A will be substituted by C and not B, so there will be no way to do it because when the cout line is reached the preprocessor had already substituted A by C.
So the short answer is, it's not possible because the preprocessor would have replaced A with C before the file is compiled.

Yeah, it's possible. You just have to use a couple of cheats.
#undef B before #define EXP_STR
Use a few more levels of indirection
For example:
#define A B
#define B C
#define _TEMP_VAR B // so that it can be redefined later
#undef B // so that EXP_STR(A) will return "B"
#define EXP_STR__(x) (x)
#define EXP_STR_(x) EXP_STR__(#x)
#define EXP_STR(x) EXP_STR_(x)
#define STR(x) # x
#define B _TEMP_VAR // now you can still access A normally, defined to B (defined to C)
A test program to prove it:
#include <stdio.h>
int main(void)
{
printf( "EXP_STR(A) = %s\n", EXP_STR(A) );
printf( "STR(A) = %s\n", STR(A) );
}
Output:
EXP_STR(A) = B
STR(A) = A

Related

Evaluate macro depending if another macro is defined

The following preprocessor-based identifier-to-string lookup table:
#include <iostream>
// included generated file
#define KEY_a valueA
#define KEY_b valueB
///////
#define LOOKUP_(_key_) KEY_ ## _key_
#define QUOTE_(_str_) #_str_
#define EXPAND_AND_QUOTE_(_str_) QUOTE_(_str_)
#define LOOKUP(_key_) EXPAND_AND_QUOTE_(LOOKUP_(_key_))
int main() {
std::cout << LOOKUP(a) << std::endl;
std::cout << LOOKUP(b) << std::endl;
std::cout << LOOKUP(c) << std::endl;
}
Output:
valueA
valueB
KEY_c
The first #defines come from an #included header generated by an external script before the compilation.
The LOOKUP macro correctly handles existing key in the table, and substitutes the given value as string literal.
But for non-existing keys, it substitutes the key as string literal.
Is there a way to instead make it substitute a given constant for non-existing keys, without causing a compile-time error, and all within the preprocessing stage?
So for example, the LOOKUP(c) and LOOKUP(whatever) should all be substituted to "undefined", without c or whatever occuring in the included generated file.
The names of the keys should not be outputted to the compiled binary, so ideally they should never be seen by the compiler.
Here's a simple, if hacky, solution. By making the definition of KEY_x a list of two elements (the first of which will be ignored), it permits adding a default value:
#include <iostream>
// included generated file
#define KEY_a _,valueA
#define KEY_b _,valueB
///////
#define LOOKUP_(key) KEY_ ## key
#define QUOTE_(_,str,...) #str
#define EXPAND_AND_QUOTE_(...) QUOTE_(__VA_ARGS__)
#define LOOKUP(key) EXPAND_AND_QUOTE_(LOOKUP_(key),undefined)
int main() {
std::cout << LOOKUP(a) << std::endl;
std::cout << LOOKUP(b) << std::endl;
std::cout << LOOKUP(c) << std::endl;
}
Test on coliru

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);
}

c++ get macro name in macro

How to get the macro name inside a macro?
Say we have:
#include <iostream>
using std::cout;
using std::endl;
#define MACRO() \
cout << __MACRO_NAME__ << endl
int main () {
MACRO();
return 0;
}
Expected output:
MACRO
Did little bit of research and I don't think that is doable in c++.
But you could use this:
#define MACRO2(x) cout << #x << endl
#define MACRO MACRO2(MACRO)
In this you can use MACRO2 to do the task of MACRO and you can also access name of MACRO as an argument x.

Token pasting and __LINE__

I'm writing a simple macro to show TRACE information.
This is what I'm using ,
#ifdef __DEBUG__
#define TRACE { PrintErrorMsg("Trace exception at " __FILE__ "LineNo:"##(__LINE__) "Function: " __FUNCTION__ " " );}
#else
#define TRACE
#endif
This is working with FILE, but it doesn't seems to work with LINE ,
Any idea how could I deal with this. I already tried stringing operator too.Which is as
bellow.
#ifdef __DEBUG__
#define TRACE { PrintErrorMsg("Trace exception at " __FILE__ "LineNo:"#(__LINE__) "Function: " __FUNCTION__ " " );}
#else
#define TRACE
#endif
and without parms and with double parms , ex - __LINE__ or ((__LINE__))
Any idea how could I deal with this problem?
And I come up with this,
#ifdef __DEBUG__
#define ERROR_MSG_BUF_SIZE 1024
#define TRACE { char * error_msg_buffer = new char[ERROR_MSG_BUF_SIZE]; \
sprintf(error_msg_buffer,"Trace Exception at file: %s ,Line : %d , Function %s \n",__FILE__,__LINE__,__FUNCTION__);\
PrintErrorMsg(error_msg_buffer );\
delete[] error_msg_buffer;}
#else
#define TRACE
But I want to do it without using sprintf , just only by stringing and token pasting.
Any idea?
#endif
--Thanks in advance--
When you try to stringize something with #x, that x must be a macro parameter:
#define FOO #__LINE__ /* this is not okay */
#define BAR(x) #x /* this is okay */
But you cannot simply say BAR(__LINE__), because this will pass the token __LINE__ into BAR, where it is immediately turned into a string without expansion (this is by design), giving "__LINE__". The same thing happens with the token-pasting operator ##: expansion of their operands never happens.
The solution is to add indirection. You should always have these in your codebase somewhere:
#define STRINGIZE(x) STRINGIZE_SIMPLE(x)
#define STRINGIZE_SIMPLE(x) #x
#define CONCAT(first, second) CONCAT_SIMPLE(first, second)
#define CONCAT_SIMPLE(first, second) first ## second
Now STRINGIZE(__LINE__) turns to STRINGIZE_SIMPLE(__LINE__) which gets fully expanded to (for example) #123, which results in "123". Phew! I leave STRINGIZE_SIMPLE around on the off chance I want the original behavior. So your code would be something like:
#include <iostream>
#define STRINGIZE(x) STRINGIZE_SIMPLE(x)
#define STRINGIZE_SIMPLE(x) #x
#define TRACE() \
PrintErrorMsg("Trace exception in " __FILE__ \
" at line number " STRINGIZE(__LINE__) \
" in function " __FUNCTION__ ".")
void PrintErrorMsg(const char* str)
{
std::cout << str << std::endl;
}
int main()
{
TRACE();
}
You need this kind of silliness, unfortunately.
#include <stdio.h>
#define TRACE2(f,l) printf("I am at file: " f " and line: " #l "\n")
#define TRACE1(f,l) TRACE2(f,l)
#define TRACE() TRACE1(__FILE__, __LINE__)
int main(void)
{
TRACE();
TRACE();
}
I am at file: test.cpp and line: 9
I am at file: test.cpp and line: 10