I was working on a small application that I'm building a simple CLI for. I wanted my CLI to have some colors because who likes boring old white and black consoles?? (jk no offense if you do:))
Then as I was building onto it I seem to have run into a problem that I, unfortunately, don't understand :(. The problem lies in some borrowed code that is supposed to help me clean the code by wrapping all the necessary code into neat little functions or definitions (you'll see what I'm talking about soon). I don't really know how definitions work in C++ or at least the more advanced ones but here is the code I currently have for wrapping the CLI color code functions into:
Colors.h
#ifndef _COLORS_
#define _COLORS_
/* FOREGROUND */
#define RST "\x1B[0m" // RESET
#define KRED "\x1B[31m" // RED
#define KGRN "\x1B[32m" // GREEN
#define KYEL "\x1B[33m" // YELLOW
#define KBLU "\x1B[34m" // BLUE
#define KMAG "\x1B[35m" // MAGENTA
#define KCYN "\x1B[36m" // CYAN
#define KWHT "\x1B[37m" // WHITE
#define FRED(x) KRED x RST
#define FGRN(x) KGRN x RST
#define FYEL(x) KYEL x RST
#define FBLU(x) KBLU x RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST
#define BOLD(x) "\x1B[1m" x RST // BOLD
#define UNDL(x) "\x1B[4m" x RST // UNDERLINE
#endif /* _COLORS_ */
So the problem is that this below works:
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
and this doesn't...
std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;
Again, I'm not too familiar with how "defined functions" work but I was just wondering if anybody could possibly show me a new method that accepts both the raw text input and a variable input to the defined functions. Also if you could help me understand how definitions work more in C++ that would be awesome as well.
Macros work the same way as if you copy-pasted the macro definition to the place where it's used.
So this works:
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
// same as
std::cout << "\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m" << std::endl;
// same as
std::cout << "\x1B[34mHello, World. I'm blue!\x1B[0m" << std::endl;
(C++ has a rule whereby adjacent string literals get joined together. I imagine this rule was added so that you can do exactly what you're doing here)
And this doesn't work:
std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;
// same as
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
// oops, syntax error
The difference is because FBLU is a preprocessor macro (and NOT a function) that works as you expect ONLY if its parameter is a string literal. The preprocessor does TEXT substitution to produce source code - which is passed to a later phase of compilation.
The preprocessor will turn
FBLU("Hello, World. I'm blue!")
into
KBLU "Hello, World. I'm blue!" RST
which (by substituting the macros KBLU and RST) becomes
"\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m"
which is a set of string literals, which get appended (again by the preprocessor) to become a single string literal
"\x1B[34mHello, World. I'm blue!\x1B[0m"
The net effect is that
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
is seen by the compiler as
std::cout << "\x1B[34mHello, World. I'm blue!\x1B[0m" << std::endl;
which is a perfectly valid code statement.
This doesn't work for
std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;
since
FBLU(randomString)
is preprocessed to become
KBLU randomString RST
which (by substituting the macros KBLU and RST) becomes
"\x1B[34m" randomString "\x1B[0m"
Now, since randomString is an identifier (name of a variable, in this case), the preprocessor does no further macro substitution, and
std::cout << FBLU(randomString) << std::endl;
is seen by the compiler as
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
which is not a valid statement.
The difference (depending on whether the argument to FBLU() is a string literal or a variable) is one of many reasons that usage of macros is actively discouraged in C++.
There are various alternatives that can be used instead, but the essential guideline is "Don't use macros".
For example, change the header files to convert the macros with no arguments into variable declarations, such as
#include <string> // needed in the header since we're using std::string
/* FOREGROUND */
const std::string RST = "\x1B[0m"; // RESET
const std::string KRED = "\x1B[31m"; // RED
// etc
and the macros with arguments into inline functions
inline std::string FRED(const std::string &x)
{
return KRED + x + RST;
}
After doing this, both of your examples will work as expected.
You are concatenating strings with macros, macros are not functions. You can't invoke macros with variables. For example the following program will print "hello world"
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "hello " "world" << endl;
}
See https://wandbox.org/permlink/EbG5ZUgVfKLo9lEq
So when you "invoke" the macro, after preprocessing your code looks like this
std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
std::cout << "\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m" << std::endl;
You are essentially combining the arguments to the macro together before compilation at preprocessing time. So with variables in your example you get the following
std::cout << FBLU(randomString) << std::endl;
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
Which is ill formed C++, since you can't concatenate non string literals with string literals like that.
Remember that macros do nothing but plain text replacement.
The compilation of a C++ program involves three steps: preprocessing, compilation, linking.
So, you see, preprocessing goes first. At that time content of variable is not known to preprocessor, so your second code snippet unrolls to the following:
std::string randomString = "Hello, World. I'm blue!";
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
which produces syntax error.
Related
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
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);
}
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"
In the absence of help from Google, I wonder if someone could tell me if it is possible to create a C++ (g++) debug macro that acts like, for example, an "improved" std::cout. Idea is to accept args via << and to append some text so that
DBG << "Hello" << world;
might produce
myfile.cpp 1420 Hello world
I know there are logging libraries(?)/macros(?) out there that do this sortof thing. I'm interested in how it's done, not using some package.
Your macro could create a temporary variable which invokes endl on destruction. The temporary will stick around until the enclosing expression ends, typically at the ;.
#include <iostream>
struct X {
~X() { std::cout << std::endl; }
};
#define DBG (X(), std::cout << __FILE__ << " " << __LINE__ << " ")
int main () {
std::string world(", world");
DBG << "Hello" << world;
}
How about:
#define DBG std::cout << __FILE__ << " " << __LINE__ << " "
http://ideone.com/mN5n3
Close enough! Unfortunatelly, you have to declare the variable world beforehand.
The idea behind a debug macro is that it should compile to nothing if you are in release mode. Try this;
#ifdef _DEBUG
#define MESSAGE(x) (std::cout << __FILE__ << " " << __LINE__ << " " << x);
#else
#define MESSAGE(x) ;
#endif
int _tmain(int argc, _TCHAR* argv[])
{
MESSAGE("Hello");
return 0;
}
When you are in release mode, MESSAGE(x) will have no effect, but in debug mode, you will get a message to the command line.
my_macro << 1 << "hello world" << blah->getValue() << std::endl;
should expand into:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
#define my_macro my_stream()
class my_stream: public std::ostringstream {
public:
my_stream() {}
~my_stream() {
ThreadSafeLogging(this->str());
}
};
int main() {
my_macro << 1 << "hello world" << std::endl;
}
A temporary of type my_stream is created, which is a subclass of ostringstream. All operations to that temporary work as they would on an ostringstream.
When the statement ends (ie. right after the semicolon on the whole printing operation in main()), the temporary object goes out of scope and is destroyed. The my_stream destructor calls ThreadSafeLogging with the data "collected" previously.
Tested (g++).
Thanks/credits to dingo for pointing out how to simplify the whole thing, so I don't need the overloaded operator<<. Too bad upvotes can't be shared.
Couldn't you just derive from ostream and provide your own thread safe implementation? Then you could just do
myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;
And get the exact same functionality without macros and using C++ properly?
No. The problem is that without using function syntax, a macro is limited to only being replaced where it is.
But if you were willing to use function syntax, you can then replace stuff both before and after the args.
my_macro(1 << "hello world" << blah->getValue() << std::endl);
You could by defining MyMacro as:
#define my_macro(args) std::ostreamstring oss; \
oss << args; \
ThreadSafeLogging(oss.str());
Take a look at google-glog, they do this using a temporary object instanciated with a
LOG(INFO) << "log whatever" << 1;
and they also have other interesting macros such as LOG_IF et al.
Considering you have these lines included somewhere in your code, yes it is possible
#include <iostream>
#include <sstream>
__LINE__ macro is defined by all standart compilers.
So we can use it to generate a variable name wich is different each time you use the macro :)
Here is a new version that is seen as a one-statement instruction only:
(EDITED)
#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
Var(s, __LINE__).x<2; ++Var(s, __LINE__).x) \
if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
else Var(s, __LINE__).oss
// So you can use it like this
int main()
{
if (4 != 2)
my_macro << 4 << " hello " << std::endl;
my_macro << 2 << " world !" << std::endl;
}
Developper probably won't need to use this macro twice on same line becasue of simplicity of operator <<. But in case you need this, you can switch the use of __LINE__ by __COUNTER__ (which is non standard!). Thanks to Quuxplusone for this tip
Here's another nasty trick I saw somewhere else. It has a significant disadvantage compared to my other answer: you can't use it twice in the same scope because it declares a variable. However, it may still be interesting for other cases where you want to have somemacro foo run something after foo.
#define my_macro \
std::ostringstream oss; \
for (int x=0; x<2; ++x) \
if (x==1) ThreadSafeLogging(oss.str()); \
else oss
int main() {
my_macro << 1 << "hello world" << std::endl;
}
The logging setup I have is quite similar:
bool ShouldLog(const char* file, size_t line, Priority prio);
class LoggerOutput : public std::stringstream {
public:
LoggerOutput(const char* file, size_t line, Priority prio)
: prio(prio)
{
Prefix(file, line, prio);
}
void Prefix(const char* file, size_t line, Priority prio);
~LoggerOutput() {
Flush();
}
void Flush();
private:
Priority prio;
};
#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)
If your logging is disabled, the ostream is never created and little overhead exists. You can configure logging on file name & line number(s) or priority levels. The ShouldLog function can change between invocations, so you could throttle or limit output. The log output uses two functions to modify itself, Prefix that adds a "file:line: (PRIO) " prefix to the line, and Flush() which both flushes it to the log output as a single command and adds a newline to it. In my implementation it always does, but you can make that conditional if one is not already there.