Macro argument stringification to wide string literal in C/C++ preprocessor - c++

C preprocessor has a feature called stringification. It's a feature that allows to create a (narrow) string literal from a macro parameter. It can be used like this:
#define PRINTF_SIZEOF(x) printf("sizeof(%s) == %d", #x, sizeof(x))
/* stringification ^^ */
Usage example:
PRINTF_SIZEOF(int);
...might print:
sizeof(int) == 4
How to create a wide string literal from a macro parameter? In other words, how can I implement WPRINTF_SIZEOF?
#define WPRINTF_SIZEOF(x) wprintf( <what to put here?> )

In order to produce a wide string literal from a macro argument, you need to combine stringification with concatenation.
WPRINTF_SIZEOF can be defined as:
#define WPRINTF_SIZEOF(x) wprintf(L"sizeof(%s) == %d", L ## #x, sizeof(x))
/* concatenation ^^ ^^ stringification */
In order to (arguably) increase readability, you can extract this trick into a helper macro:
#define WSTR(x) L ## #x
#define WPRINTF_SIZEOF(x) wprintf(L"sizeof(%s) == %d", WSTR(x), sizeof(x))

Related

How to concatenate literal strings with numerical macro?

How to make a literal string by merging a non string macro as follow?
#define SOC 12
printf("This is the default SoC:" SOC "!");
[UPDATE]
This is embedded cpp 11 and I'd like to limit resource usage so I need a compile-time solution, not runtime.
With preprocessor, you might stringify the value:
#define STRINGIFY(s) #s
#define STRINGIFY_VALUE(s) STRINGIFY(s)
and then use concatenation of C-strings:
printf("This is the default SoC:" STRINGIFY_VALUE(SOC) "!");
Demo

Variadic macro without arguments

I am using some logging macros, which are supposed to print out the information provided by the __PRETTY_FUNCTION__ macro and if needed name and value of up to two arguments.
A simplified version of my code looks like
template<typename Value1, typename Value2>
void Log(std::string const& function,
std::string const& variable_1 = "", Value1 value_1 = Value1(0),
std::string const& variable_2 = "", Value2 value_2 = Value2(0)) {
std::cout << function << " "
<< variable_1 << " " << value_1 << " "
<< variable_2 << " " << value_2 << std::endl;
}
#define LOG0() Log(__PRETTY_FUNCTION__)
#define VARIABLE(value) #value, value
#define LOG1(value) Log(__PRETTY_FUNCTION__, VARIABLE(value))
#define LOG2(value, value1) Log(__PRETTY_FUNCTION__, VARIABLE(value), VARIABLE(value1))
#define LOG(arg0, arg1, arg2, arg, ...) arg
#define CHOOSE(...) LOG(,##__VA_ARGS__, LOG2, LOG1, LOG0)
#define Debug(...) CHOOSE(__VA_ARGS__)(__VA_ARGS__)
I can use these macros like
Debug();
int x = 0;
Debug(x);
int y = 1;
Debug(x, y);
When I compile this code with clang I get a nice output containing class and function information as well as name and value of the variables.
But I also get the warning that standard compliant code is not allowed to have zero variadic arguments.
warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
#define CHOOSE(...) LOG(,##__VA_ARGS__, LOG2, LOG1, LOG0)
^
warning: must specify at least one argument for '...' parameter of variadic macro [-Wgnu-zero-variadic-macro-arguments]
Debug();
Gcc on the other hand fails to compile with
error: expected primary-expression before ‘)’ token
#define LOG1(value) Log(__PRETTY_FUNCTION__, VARIABLE(value))
^
Debug();
Obviously it is dangerous to work with zero variadic arguments.
Is there any way that I can turn this code into standard compliant code without removing the convenience of having just one macro that takes zero to two arguments?
If this is not possible, is there a way to make also gcc compile this code?
The hard part of this is distinguishing between Debug() and Debug(x). In both cases, you are technically passing a single argument to the macro Debug. In the first case, the token sequence of that argument is empty, and in the second case it contains a single token. These cases can be distinguished with a trick due to to Jens Gustedt.
Here's the trick:
#define COMMA_IF_PARENS(...) ,
Observe that COMMA_IF_PARENS X produces a comma if X starts with (...), and otherwise expands to a token sequence containing no additional (top-level) commas. Likewise, COMMA_IF_PARENS X () produces a comma if X is empty or starts with (...) and otherwise expands to a token sequence containing no additional (top-level) commas. (In each case, the token sequence also contains all the top-level commas from X itself.)
We can use that trick like this:
#define CHOOSE(...) \
LOG(__VA_ARGS__ \
COMMA_IF_PARENS __VA_ARGS__ \
COMMA_IF_PARENS __VA_ARGS__ (), \
CHOICES)
Note that:
COMMA_IF_PARENS __VA_ARGS__ produces the number of commas in __VA_ARGS__ plus 1 if __VA_ARGS__ starts with (...).
COMMA_IF_PARENS __VA_ARGS__ () produces the number of commas in __VA_ARGS__ plus 1 if __VA_ARGS__ is empty or starts with (...). (Note that this can fail if __VA_ARGS__ ends in the name of a function-like macro, and we don't address that potential problem here.)
Let c be the number of commas in __VA_ARGS__, p be 1 if __VA_ARGS__ starts with (...) and 0 otherwise, and e be 1 if __VA_ARGS__ is empty and 0 otherwise.
The number of macro arguments produced prior to CHOICES is 3 c + 2 p + e. Taken modulo 3, the number of commas is 0 or 2 for a normal argument, and 1 if we have an empty list of arguments.
This gives us 6 cases we care about:
#define CHOICES LOG2, impossible, LOG2, LOG1, LOG0, LOG1
#define LOG(a0, a1, a2, a3, a4, a5, arg, ...) arg
However, this doesn't quite work, because we need to delay expanding the LOG(...) macro invocation until after we expand the COMMA_IF_PARENS machinery. One way to do that is:
#define LPAREN (
#define EXPAND(...) __VA_ARGS__
#define CHOOSE(...) EXPAND(LOG LPAREN COMMA_IF_PARENS [...]))
We also should add another comma to the end of CHOICES so that we always have a (possibly empty) argument corresponding to the ... parameter of LOG.
Putting it all together, we get this:
#define COMMA_IF_PARENS(...) ,
#define LPAREN (
#define EXPAND(...) __VA_ARGS__
#define CHOOSE(...) \
EXPAND(LOG LPAREN \
__VA_ARGS__ COMMA_IF_PARENS __VA_ARGS__ COMMA_IF_PARENS __VA_ARGS__ (), \
LOG2, impossible, LOG2, LOG1, LOG0, LOG1, ))
#define LOG(a0, a1, a2, a3, a4, a5, arg, ...) arg
with everything else unchanged from your code. (This can be generalized much further, but the above is sufficient to demonstrate the technique.)

How to remove the enclosing parentheses with macro?

No comma is allowed in a macro argument because it will be treated as more than one arguments and the preprocessing will be wrong. However, we can parenthesize the argument to let preprocessor treat it as one argument. Is there a macro or other techniques which can remove the enclosing parentheses?
For example, if I define a macro like
#define MY_MACRO(a, b) ...
and use it like
MY_MACRO( A<int, double>, text );
will be wrong. use it like
MY_MACRO( (A<int, double>), text)
with a macro or technique to remove the parentheses will be fine. Boost provides BOOST_IDENTITY_TYPE macro for only types but not general cases
#define ESC(...) __VA_ARGS__
then
MY_MACRO( ESC(A<int, double>), text );
might do what you want.
This macro trick is similar to Yakk's solution but removes the need to explicitly pass in another macro as a parameter.
#include <stdio.h>
#define _Args(...) __VA_ARGS__
#define STRIP_PARENS(X) X
#define PASS_PARAMETERS(X) STRIP_PARENS( _Args X )
int main()
{
printf("without macro %d %d %d %d %d %d\n", (5,6,7,8,9,10) ); // This actually compiles, but it's WRONG
printf("with macro %d %d %d %d %d %d\n", PASS_PARAMETERS((5,6,7,8,9,10)) ); //Parameter "pack" enclosed in parenthesis
return 0;
}
Of course you could get creative by making the PASS_PARAMETERS macro into a variadic macro and pass in multiple parameter packs.
Only maybe removing parentheses:
If you need to strip one layer of parenthesis, but only if there are parenthesis to strip, this longer set of macros does the trick:
#define DEPAREN(X) ESC(ISH X)
#define ISH(...) ISH __VA_ARGS__
#define ESC(...) ESC_(__VA_ARGS__)
#define ESC_(...) VAN ## __VA_ARGS__
#define VANISH
This may be needed if you want to use MY_MACRO for different sets of datatypes:
#define MY_MACRO(a, b) DEPAREN(a), b
MY_MACRO( ({x, y, z}), text )
//> {x,y,z}, text
MY_MACRO( singlearg, text )
//> singlearg, text
How it works:
We start with DEPAREN(X) ESC(ISH X). If X has parenthesis, we get ESC(ISH(X)). If X does not have parenthesis, we get ESC(ISH X).
We then expand ESC(...) into ESC_(__VA_ARGS__), which expands the interior.
ISH(...) turns into ISH __VA_ARGS__, which strips one layer of parentheses from X. Now, regardless of whether or not X originally had parenthesis, we have ESC_(ISH X).
We now need to get rid of ISH. However, because we already defined ISH(...), we can't also define it as #define ISH . That's why we concatenate it with another token (VAN) to get VANISH X.
VANISH is defined as , so we are finally left with X, sans parentheses.
A simple hack could be to use variadic macros:
#define MY_MACRO(a, b...) ...
Then you can use it like:
MY_MACRO(text, A<int, double>)
The comma in the second argument is still interpreted as the argument separator (meaning the macro is actually called with three arguments), but it's expanded inside the macro, making the behavior the same. The variadic argument has to be last in the macro, however.

C/C++ macro string concatenation

#define STR1 "s"
#define STR2 "1"
#define STR3 STR1 ## STR2
Is it possible to concatenate STR1 and STR2, to "s1"?
You can do this by passing args to another Macro function. But is there a direct way?
If they're both strings you can just do:
#define STR3 STR1 STR2
This then expands to:
#define STR3 "s" "1"
and in the C language, separating two strings with space as in "s" "1" is exactly equivalent to having a single string "s1".
You don't need that sort of solution for string literals, since they are concatenated at the language level, and it wouldn't work anyway because "s""1" isn't a valid preprocessor token.
[Edit: In response to the incorrect "Just for the record" comment below that unfortunately received several upvotes, I will reiterate the statement above and observe that the program fragment
#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")
produces this error message from the preprocessing phase of gcc: error: pasting ""s"" and ""1"" does not give a valid preprocessing token
]
However, for general token pasting, try this:
/*
* Concatenate preprocessor tokens A and B without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define PPCAT_NX(A, B) A ## B
/*
* Concatenate preprocessor tokens A and B after macro-expanding them.
*/
#define PPCAT(A, B) PPCAT_NX(A, B)
Then, e.g., both PPCAT_NX(s, 1) and PPCAT(s, 1) produce the identifier s1, unless s is defined as a macro, in which case PPCAT(s, 1) produces <macro value of s>1.
Continuing on the theme are these macros:
/*
* Turn A into a string literal without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define STRINGIZE_NX(A) #A
/*
* Turn A into a string literal after macro-expanding it.
*/
#define STRINGIZE(A) STRINGIZE_NX(A)
Then,
#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"
By contrast,
STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"
#define T1T2 visit the zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"
Hint: The STRINGIZE macro above is cool, but if you make a mistake and its argument isn't a macro - you had a typo in the name, or forgot to #include the header file - then the compiler will happily put the purported macro name into the string with no error.
If you intend that the argument to STRINGIZE is always a macro with a normal C value, then
#define STRINGIZE(A) ((A),STRINGIZE_NX(A))
will expand it once and check it for validity, discard that, and then expand it again into a string.
It took me a while to figure out why STRINGIZE(ENOENT) was ending up as "ENOENT" instead of "2"... I hadn't included errno.h.

C++ Macros: manipulating a parameter (specific example)

I need to replace
GET("any_name")
with
String str_any_name = getFunction("any_name");
The hard part is how to trim off the quote marks. Possible? Any ideas?
How about:
#define UNSAFE_GET(X) String str_##X = getFunction(#X);
Or, to safe guard against nested macro issues:
#define STRINGIFY2(x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2(a, b) a##b
#define PASTE(a, b) PASTE2(a, b)
#define SAFE_GET(X) String PASTE(str_, X) = getFunction(STRINGIFY(X));
Usage:
SAFE_GET(foo)
And this is what is compiled:
String str_foo = getFunction("foo");
Key points:
Use ## to combine macro parameters into a single token (token => variable name, etc)
And # to stringify a macro parameter (very useful when doing "reflection" in C/C++)
Use a prefix for your macros, since they are all in the same "namespace" and you don't want collisions with any other code. (I chose MLV based on your user name)
The wrapper macros help if you nest macros, i.e. call MLV_GET from another macro with other merged/stringized parameters (as per the comment below, thanks!).
One approach is not to quote the name when you call the macro:
#include <stdio.h>
#define GET( name ) \
int int##name = getFunction( #name ); \
int getFunction( char * name ) {
printf( "name is %s\n", name );
return 42;
}
int main() {
GET( foobar );
}
In answer to your question, no, you can't "strip off" the quotes in C++. But as other answers demonstrate, you can "add them on." Since you will always be working with a string literal anyway (right?), you should be able to switch to the new method.