I've read different related answers on StackOverflow but none of them gives me the answer to this question.
I need to do concatenation of entities (not necessarily strings) passed to the macro with a separator between them (in my case dot). Here is my code:
#define STR(x) #x
#define XSTR(x) STR(x)
#define CONC_(a, b) a ## b
#define CONC(a, b) CONC_(a, b)
#define CONC3(_1, _2, _3, S) CONC2(CONC2(_1, _2, S), _3, S)
#define CONC2(_1, _2, S) CONC(_1, CONC(S, _2))
#define JOIN_UNDERSCORE(_1, _2, _3) XSTR(CONC3(_1, _2, _3, _))
#define JOIN_DOT(_1, _2, _3) XSTR(CONC3(_1, _2, _3, .)) // here I pass dot
Here is how you can use it
std::string underscore = JOIN_UNDERSCORE(one, two, three);
std::string dot = JOIN_DOT(one, two, three); // this one doesn't compile
I could use another technique to achieve this. Like:
#define APPEND_DOT(x) "." STR(x)
#define CONCSTR3(_1, _2, _3) CONCSTR2(_1, _2) APPEND_DOT(_3)
#define CONCSTR2(_1, _2) STR(_1) APPEND_DOT(_2)
#define CONCSTR1(_1) STR(_1)
#define JOIN_STR_DOT(_1, _2, _3) CONCSTR3(_1, _2, _3)
std::string dot_str = JOIN_STR_DOT(one, two, three);
and this would work with dot. But the question is how to make it generic by passing the separator.
Here is a link to play around https://godbolt.org/z/MDxsJS
The result of the ## operator must be a valid pre-processor token. one_ is valid, one. is not. That's why underscore works but dot doesn't.
If the intention is to create a string, you can utilize pre-processor string literal concatenation rathern than the token paste operator:
#define STR(x) #x
#define JOIN_UNDERSCORE(_1, _2, _3) STR(_1) "_" STR(_2) "_" STR(_3)
which can be written generically as:
#define STR(x) #x
#define JOIN_SYMBOL(_1, _2, _3, symbol) STR(_1) STR(symbol) STR(_2) STR(symbol) STR(_3)
...
const char* underscore = JOIN_SYMBOL(one, two, three, _);
const char* dot = JOIN_SYMBOL(one, two, three, .);
This can't be used to create variable names, but then dots can't be used to create variable names either.
It is possible to do this by skipping the concatenation entirely, but what good that would do, I have no idea:
#define DUMB_THING(_1, _2, _3, thingie) _1 thingie _2 thingie _3
#include <stdio.h>
int main (void)
{
typedef struct { int idea; } stupid_t;
typedef struct { stupid_t stupid; } really_t;
really_t really;
DUMB_THING(really, stupid, idea, .) = 42;
printf("%d", really.stupid.idea);
}
## allows to concatenate valid preprocessing tokens forming a valid preprocessing token.
In your case, you could use
std::string pi = CONCSTR2(3, 141592);
as 3, 3. and 3.141592 are all valid preprocessing tokens. But you can't use
std::string dot = JOIN_DOT(one, two, three);
as .two (which is the first concatenation you are doing) is not a valid preprocessing token. When your final goal is to form a string, better use the string literal concatenation available by juxtaposition. When your goal is an identifier, you can use your first method.
Related
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))
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.)
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.
For a lot of function calls in a C app that needs some degree of debugging I wanted to add a macro to ease the typing that I had to do.
right now I am calling a function like this:
aDebugFunction(&ptrToFunction, __LINE__, "ptrToFunction", param1, param2, etc)
So I thought lets write a macro that does the first 3 parameters for me, like this:
#define SOMEDEFINE(x) &x, __LINE__, "x"
However, as most of you will immediately know, this won't work it won't replace "x" with the name that x has been given but will just pass "x" as 3rd parameter.
My knowledge of this preprocessor macro happening stuff is quite limited and thus my googling-ability is also quite useless due to not knowing where to search for exactly.
I hope one of you guys/girls could give me either a solution or point me in the right direction.
You need to use the # convert token to string command of the preprocessor. You should define your second macro this way:
#define SOMEDEFINE(x) &x, __LINE__, # x
Or if x can also be a macro call, and you want the string to contains the expansion of the macro, you need to use an auxiliary macro:
#define TOKEN_TO_STRING(TOK) # TOK
#define STRINGIZE_TOKEN(TOK) TOKEN_TO_STRING(TOK)
#define SOMEDEFINE(x) &x, __LINE__, STRINGIZE_TOKEN(x)
For example, if you have the following code:
#define SHORT_NAME a_very_very_very_long_variable_name
SOMEDEFINE(SHORT_NAME)
Then, with the first macro, it will expand to
&a_very_very_very_long_variable_name, __LINE__, "SHORT_NAME"
While, with the second macro, it will expand to:
&a_very_very_very_long_variable_name, __LINE__, "a_very_very_very_long_variable_name"
You can actually do a lot better than that: #define SOMEDEFINE( X, ... ) aDebugFunction( &(X), __LINE__, #X, __VA_ARGS__ )
You could then simply call into this code like this: SOMEDEFINE( ptrToFunction, param1, param2, etc )
And that would effectively call: aDebugFunction( &( ptrToFunction ), __LINE__, "ptrToFunction", param1, param2, etc )
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.