Given the below, how can I get something that yields ONE TWO THREE? I can't seem to figure out what to put in ?? to yield the intended concat behavior. You can't seem to #define a single space.
#include <iostream>
#define STRINGIFY(x) #x
#define STRINGIFYMACRO(y) STRINGIFY(y)
#define CONCAT2(X,Y) X ## Y
#define CONCAT(X,Y) CONCAT2(X,Y)
#define CAT \
ONE \
TWO
#define DOG \
THREE
#define BAT CONCAT(CONCAT(CAT,?? ),DOG)
int main()
{
std::cout << STRINGIFYMACRO(BAT) << std::endl;
return 0;
}
The ## operator is used to combine two consecutive tokens. It cannot be used to combined things that are not tokens (such as whitespace), nor can it be used if the result is not a valid (preprocessing) token.
In other words, don't use ## to combine strings. That's not what it is for, and it won't work.
Remember that in C++, consecutive strings will be concatenated by the compiler. So there is normally no need to concatenate the contents of the string. Even if you had to concatenate the contents, you could do that without token concatenation because the contents of a string are not a token. (This is only necessary if you are trying to create a computed #include filename from multiple components.)
One other useful thing to know is that whitespace inside a macro replacement (not at either end) is reduced to a single space character, which is preserved by the stringify operator.
So if you're OK with the single space character, you can just do this:
#include <iostream.h>
#define STRINGIFY(x) #x
#define STRINGIFY_EXPANDED(x) STRINGIFY(x)
#define CAT ONE TWO
#define DOG THREE
#define BAT CAT DOG
int main() {
std::cout << STRINGIFY_EXPANDED(BAT) << '\n';
return 0;
}
Try it online!
Otherwise, you could stringify in pieces and concatenate the pieces as desired:
#define DOG STRINGIFY(ONE) " " STRINGIFY(TWO)
#define CAT STRINGIFY(THREE)
#define BAT DOG "\t" CAT
Try it online!
Related
The 1 seems unnecessary (and possibly misleading) in the following example, but I have seen this multiple times when used for checking #ifdefs:
#ifndef __NEWLIB_H__
#define __NEWLIB_H__ 1
Is there a difference or reason for using the above versus a plain #define __NEWLIB_H__?
1 is true, so you can use the macro in an #if test. That's not usually very useful for header guards, but it certainly doesn't hurt. For other macros which might be tested in boolean expressions, the true value is definitely useful.
Some people just like the consistency. And that's the definition that gcc chooses by default if you put -D TESTME on the command line.
However,
#define __NEWLIB_H__ 1
is not cool unless it's in an implementation of the standard library, because names starting with two underscores (or an underscore and a capital letter) are reserved for use by the implementation, and should never be used in portable applications.
When used purely as an #include guard, there is no difference between
#ifndef __NEWLIB_H__
#define __NEWLIB_H__
and
#ifndef __NEWLIB_H__
#define __NEWLIB_H__ 1
However, in general, there is a distinction.
Compiler error
#ifndef ABCD
#define ABCD
#endif
int main()
{
#if defined(ABCD) && (ABCD == 1)
std::cout << "ABCD is 1\n";
#else
std::cout << "ABCD is not 1\n";
#endif
}
Outputs the string "ABCD is 1"
#ifndef ABCD
#define ABCD 1
#endif
int main()
{
#if defined(ABCD) && (ABCD == 1)
std::cout << "ABCD is 1\n";
#else
std::cout << "ABCD is not 1\n";
#endif
}
Outputs the string "ABCD is not 1"
#ifndef ABCD
#define ABCD 10
#endif
int main()
{
#if defined(ABCD) && (ABCD == 1)
std::cout << "ABCD is 1\n";
#else
std::cout << "ABCD is not 1\n";
#endif
}
#define by itself will replace the symbol with nothing.
On the other hand, #define 1, as you call it, will replace the symbol with 1 everywhere it is found in the file. So, for example, the following code:
#include <iostream>
#define EXAMPLE "hello"
int main()
{
std::cout << EXAMPLE;
return 0;
}
prints
hello
This is because EXAMPLE here is replaced with "hello", making the print statement equivalent to:
std::cout << "hello";
If we change the #define statement to this instead:
#define EXAMPLE
This will give a compile error:
main.cpp: In function ‘int main()’:
main.cpp:15:25: error: expected primary-expression before ‘;’ token
std::cout << EXAMPLE;
As to why you would ever use this second form of #define, it's because there is another processor directive that you can use called #ifdef:
#include <iostream>
#define EXAMPLE
int main()
{
#ifdef EXAMPLE
std::cout << "EXAMPLE defined.";
#endif
return 0;
}
This will print:
EXAMPLE defined.
Because #ifdef (and its relative #ifndef) only require that the symbol be defined, we don't really need to give it a value. It just needs to be there to work.
A common place you see this kind of stuff is with header guards (which is probably what you're seeing). You can also see it with platform identification, or even to determine whether the compiler is using C++ or not.
Recently I run into strange behavior of my code:
#define STR(X) #X
#define XSTR(X) STR(X)
#define TEST_SERVER_HTTP http://host.cz/import.php
qDebug() << "Test server: " XSTR(TEST_SERVER_HTTP);
outputting just "http:" text.
I have figured out, that the "//" part of the URL is here interpreted as C++ comment, cutting the rest of URL text away.
Obvious workaround would be
#define TEST_SERVER_HTTP http:\/\/host.cz\/import.php
however I am getting (G++) warning
invalid string literal, ignoring final '\' [enabled by default]
wherever macro is used, even though the compiled code runs as expected.
Questions are:
Is there some "correct" way in C++ how to quote slash to suppress double slash meaning of start of comment ?
Is there some "canonical" workaround for putting URL constants as replace value of object-like macro ?
And no
#define TEST_SERVER_HTTP "http://host.cz/import.php"
is not acceptable for reasons given in the rest of my code.
It can be done easily, but you need to hack into it (as always):
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#define SLASH() /
#define DOUBLE_SLASH() SLASH()SLASH()
#define STH_BEFORE() sth/before
#define STH_AFTER() sth/after
#define STH_DOUBLE_SLASH_STH STH_BEFORE()DOUBLE_SLASH()STH_AFTER()
int main()
{
//test
std::cout << STRINGIFY(STH_DOUBLE_SLASH_STH) << std::endl;
}
Output:
sth/before//sth/after
Usable new-macro-non-definiable version would be:
#define PLACEBO(x) x
#define STH_DOUBLE_SLASH_STH(x,y) PLACEBO(x)DOUBLE_SLASH()PLACEBO(y)
int main()
{
std::cout << STRINGIFY(STH_DOUBLE_SLASH_STH(before, after)) << std::endl;
}
Tested with MSVC 2015 and GCC 5.3.0.
Also note, that MSVC allows such comment (this is not sane!)
DOUBLE_SLASH() fun comment
You can't escape tokens in C/C++; the only place that backslash has an effect is inside string literals. Outside of a string literal (and when not part of a universal character name), a backslash is just a one-character token which is only valid during the preprocessing phases.
It is, however, easy enough to prevent multi-character tokens from being formed during the initial division of code into tokens, and you can do so without introducing whitespace. All you need is the identity macro:
#define I(X) X
Now you can use that to avoid the double slash becoming comments:
#define STR(X) #X
#define XSTR(X) STR(X)
#define TEST_SERVER_HTTP http:I(/)I(/)host.cz/import.php
qDebug() << "Test server: " XSTR(TEST_SERVER_HTTP);
There is no point using that on the single slash, or indeed any other character.
That solution will not, however, work to escape quotes and apostrophes (or whitespace, for that matter). As far as I know, there is no way to introduce an unmatched quote or apostrophe as a token.
Disclaimer: I didn't try that with MSVC, which is known to have a non-compliant preprocessor implementation. But it should work without issues on any standards-compliant implementation.
Is it possible to redefine a C++ #define macro using information from the macro itself? I tried the code below, but because of the way the macros are evaluated the output was not what I expected.
#include <iostream>
#define FINAL_DEFINE "ABC"
#define NEW_DEFINE FINAL_DEFINE "DEF" // Want ABCDEF
#undef FINAL_DEFINE
#define FINAL_DEFINE NEW_DEFINE // Want ABCDEF, but get empty?
int main ()
{
std::cout << FINAL_DEFINE << std::endl; // Want ABCDEF, but doesn't compile.
}
Macros in macro bodies are never expanded when the macro is defined -- only when the macro is used. That means that the definition of NEW_DEFINE is not "ABC" "DEF", it is exactly what appears on the #define line: FINAL_DEFINE "DEF".
So when you use FINAL_DEFINE, that gets expanded to NEW_DEFINE which then gets expanded to FINAL_DEFINE "DEF". At this point it will not recursively expand FINAL_DEFINE (as that would lead to an infinite loop) so no more expansion occurs.
If your compiler supports push_macro & pop_macro pragma directives, you could do this:
#include <iostream>
#define FINAL_DEFINE "ABC"
#define NEW_DEFINE FINAL_DEFINE "DEF"
int main ()
{
std::cout << FINAL_DEFINE << std::endl; // Output ABC
#pragma push_macro("FINAL_DEFINE")
#define FINAL_DEFINE "XXX"
std::cout << NEW_DEFINE << std::endl; // Output XXXDEF
#pragma pop_macro("FINAL_DEFINE")
}
After preprocessing all FINAL_DEFINE in the code will be replaced with the last thing it defined and then going to compiling step.
So you cannot redefine the macro like you want.
Your compiler should warn you about that.
I am trying to use the stringizing operator #, but I get the error stray ‘#’ in program. Here is how I am using it.
#define STR "SOME_STRING"
#define BM 8
#define NUM_OF_THREADS 8
#define VER_STR (STR #BM #NUM_THREADS)
I expect to get SOME_STRING88 for VER_STR but instead get an error. What mistake am I doing?
You need to turn the numerical constants into a string. However, #BM is an error, since the syntax is only valid for macro parameters.
So you need to force en expansion through an intermediate macro. And you may as well have a STRINGIFY macro to do it:
#include <iostream>
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#define STR "SOME_STRING"
#define BM 8
#define S_BM STRINGIFY(BM)
#define NUM_OF_THREADS 8
#define S_NUM_OF_THREADS STRINGIFY(NUM_OF_THREADS)
#define VER_STR STR S_BM S_NUM_OF_THREADS
int main() {
// your code goes here
std::cout << VER_STR;
return 0;
}
You can see the above in action at http://ideone.com/cR1KZP
EDIT
As Magnus Hoff pointed out, you can invoke STRINGIFY directly as well:
#define VER_STR STR STRINGIFY(BM) STRINGIFY(NUM_OF_THREADS)
I'm building a large C++ program with a variety of different compile-time options, selected by #defines (or the -D option).
I want to have a version string that lists a number of them as tags, and ideally, to have that version string defined as a literal, not a constant.
Currently, I'm looking at three options, none of which is ideal.
Piles of preprocessor defines
#ifdef AAA
#define AAAMSG " [A]"
#else
#define AAAMSG ""
#endif
#ifdef BBB
#define BBBMSG " [B]"
#else
#define BBBMSG ""
#endif
// ...
#define REVISION __DATE__ " " __TIME__ AAAMSG BBBMSG CCCMSG DDDMSG
Build a constant
const char *const REVISION=__DATE__ " " __TIME__
#ifdef AAA
" [A]"
#endif
#ifdef BBB
" [B]"
#endif
// ...
;
Redefine the token
#define REVISION __DATE__ " " __TIME__
#ifdef AAA
#define REVISION REVISION " [A]"
#endif
#ifdef BBB
#define REVISION REVISION " [B]"
#endif
// ...
The first one is incredibly verbose (imagine that with half a dozen independent elements) and error-prone. The second one is far better, but it creates a constant instead of a literal, so I can't use it as part of another string - example:
send(sock,"rev " REVISION "\n",sizeof(REVISION)+4,0);
It seems silly to use run-time string manipulation (an sprintf or somesuch) for a compile-time constant. The third example, of course, just straight-up doesn't work, but it is pretty much what I'm trying to do.
Is there some alternative method?
#define AAAMSG ""
#define BBBMSG ""
#ifdef AAA
#define AAAMSG " [A]"
#endif
define all your empties.. then treat it like a switch.
If you keep the types the same, you shouldn't have any issues with redefining..
Note: I am not 100% sure this works, but changing a define can be done.
Closing off this question with the comment that I'm sticking with option 1. There appears to be no way to do what I was hoping to do, so the imperfect remains. Thanks to those who contributed!