Having such a simple C++ code:
#include <iostream>
#define NS NS_Static
#define MAKESTRING(x) #x
namespace NS {
int global_x = 8;
void print_global_x() {
std::cout << MAKESTRING(NS) << "::global_x: " << global_x << std::endl;
}
}
I'h expected to get on output NS_Static::global_x: 8 BUT getting just NS::global_x: 8. I've asked a similar question earlier and the user Eljay provided me an answer to use such an extra code:
#define NS Static
#define MAKESTRING_HELPER(x) #x
#define MAKESTRING(x) MAKESTRING_HELPER(x)
It finally works but can someone please explain my why my original approach doesn't work?
Shouldn't the preprocessor (in my original approach) AT FIRST (since it's the first macro defined) run NS NS_Static macro resulting in
NS_Static and then pass that NS_Static to the stringizing MAKESTRING(x) #x macro resulting in expected NS_Static string?
That's how stringizing (#x) in the C preprocessor works.
Unlike normal parameter replacement, the argument is not macro-expanded first.
To get the parameter to macro-expand, add another layer of indirection (a no-op macro like you've discovered, will suffice).
From https://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html#Argument-Prescan
Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringized or pasted with other tokens.
In your original function:
#define NS NS_Static
#define MAKESTRING(x) #x
The marco argument is stringized, so NS will not be replaced by NS_Static.
I work on a project, and I need to simulate a recursive macro (here TEST_COLUMN). But it fail on visual 2013.
On gcc, it work correctly, but with visual, I have an error.
So, to debug this macro, I use static_assert (maybe there is a better way).
Each time, in the macros TEST_COLUMN_X(name, ...) the value of name contain ALL the parameters, and not only the first one.
If anyone have an idea to fix this.
Here is the minimal code needed to reproduce it:
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x) //transform x to char
#define EXPAND(x) x
#define NUM_ARGS_HELPER(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
//count to number of argument containing
#define NUM_ARGS(...) EXPAND(NUM_ARGS_HELPER(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) in __VA_ARGS__
//define each level of the macro
#define TEST_COLUMN_0 ;
#define TEST_COLUMN_1(name) static_assert(false,"TEST_COLUMN_1 " STR(name));
#define TEST_COLUMN_2(name,...) static_assert(false,"TEST_COLUMN_2 " STR(name)); //TEST_COLUMN_1(__VA_ARGS__)
#define TEST_COLUMN_3(name,...) static_assert(false,"TEST_COLUMN_3 " STR(name)); //TEST_COLUMN_2(__VA_ARGS__)
#define TEST_COLUMN_4(name,...) static_assert(false,"TEST_COLUMN_4 " STR(name)); TEST_COLUMN_3(__VA_ARGS__)
//tricks to call the correct macro (TEST_COLUMN_X)
#define TEST_COLUMN_N1(N,...) TEST_COLUMN_##N(__VA_ARGS__)
#define TEST_COLUMN(N,...) TEST_COLUMN_N1(N,__VA_ARGS__)
//recursive macro
#define TEST_STATIC_COLUMN(...) TEST_COLUMN(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
int main(int argc, char* argv[])
{
TEST_STATIC_COLUMN(a, b, c);
return 0;
}
Output :
main.cpp(21): error C2338: TEST_COLUMN_3 a, b, c
but it should be
main.cpp(21): error C2338: TEST_COLUMN_3 a
You can test this using the online compiler http://webcompiler.cloudapp.net/
I don't know why, but adding some call to EXPAND solve this issue:
#define TEST_COLUMN_2(name,...) static_assert(false,"TEST_COLUMN_2 " STR(name)); EXPAND(TEST_COLUMN_1(__VA_ARGS__))
#define TEST_COLUMN_3(name,...) static_assert(false,"TEST_COLUMN_3 " STR(name)); EXPAND(TEST_COLUMN_2(__VA_ARGS__))
#define TEST_COLUMN_4(name,...) static_assert(false,"TEST_COLUMN_4 " STR(name)); EXPAND(TEST_COLUMN_3(__VA_ARGS__))
#define TEST_COLUMN_N1(N,...) EXPAND(TEST_COLUMN_##N(__VA_ARGS__))
Let's say I have a macro
#define CLASS_NAME ItemsList
Later I would like to use the value of it, not as a symbol, but as wide string. And my problems begin. When I simply write (in a regular C++ code, not in macro definition):
L#CLASS_NAME
compiler gives me an error, saying token # was not expected here. When I write proxy for it
#define WSTRING(S) L#S
and use it
WSTRING(CLASS_NAME)
I will get wide string with content "CLASS_NAME". I would like to expand macro, meaning getting its value, not converting the macro name.
So how to do it properly (Visual Studio 2012)?
If you want L"ItemsList" then you can use:
#define CONCAT2(X, Y) X##Y
#define CONCAT(X, Y) CONCAT2(X, Y)
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
#define WIDEN(X) CONCAT(L, STRINGIFY(X))
And then write WIDEN(CLASS_NAME).
I need to have a string that uses a macro value which is an integer. But it's outside of any functions, so I do not want to create a variable. I'm using it in a #pragma comment.
so something like this:
#define num 7
#pragma comment(lib, "string" + num)
which would combine the string and num making it (#pragma comment(lib, "string7")
What you want to do is called stringification:
#define stringify_1(x...) #x
#define stringify(x...) stringify_1(x)
#define NUM 7
char *p = stringify(NUM);
This is inspired by __stringify macro in include/linux/stringify.h in Linux kernel helpers.
I am not completely clear on the intent, it sounds like some preprocessor capability:
http://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
From that example you find this terse explanation that seems to be what you want.
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)
==> "foo"
xstr (foo)
==> xstr (4)
==> str (4)
==> "4"
So you would be able to do something like this:
#define xstr(s) str(s)
#define str(s) #s
#define num 7
#pragma comment(lib, "string" xstr(num))
Normal string merging rules should make that all fine if it were in actual code, but I am not sure if the string will automatically merge in the pragma. That is probably implementation dependent.