The C preprocessor is passing multiple arguments as if they were a single argument. I feel pretty sure the problem is how we are calling the untouchable
macro, but every attempt we have made to alter the first
macro has failed to produce the desired result. Here is a complete code sample with comments that explain what happens and what we want to happen:
//this can be changed, but it must remain a #define to be of any use to us
#define first a,b,c
// v all code below this line cannot be altered (it's outside of our control)
#define untouchable(name, c1, c2, c3) \
wchar_t name[] = \
{ \
quote(c1), \
quote(c2), \
quote(c3) \
}
#define quote(c) L#@c
// ^ all code above this line cannot be altered (it's outside of our control)
int _tmain(int argc, _TCHAR* argv[])
{
static untouchable(mrNess, first);
// the line above is precompiled to:
// static wchar_t mrNess[] = { L'a,b,c', L, L };
// whereas we want:
// static wchar_t mrNess[] = { L'a', L'b', L'c' };
return 0;
}
We are compiling in Windows under VisualStudio.
macro expansion possible specifying __VA_ARGS__ The '...' in the parameter list represents the variadic data when the macro is invoked and the __VA_ARGS__ in the expansion represents the variadic data in the expansion of the macro. Variadic data is of the form of 1 or more preprocessor tokens separated by commas.
__VA_OPT__ is a new feature of variadic macros in C++20. It lets you optionally insert tokens depending on if a variadic macro is invoked with additional arguments. An example usage is comma elision in a standardized manner.
The invocation of the macro need not be restricted to a single logical line—it can cross as many lines in the source file as you wish. The number of arguments you give must match the number of parameters in the macro definition.
A parameterized macro is a macro that is able to insert given objects into its expansion. This gives the macro some of the power of a function. As a simple example, in the C programming language, this is a typical macro that is not a parameterized macro: #define PI 3.14159.
The problem seems to be how you define first
. You pass first
to the untouchable
macro, but it is obviously not expanded at that time.
So do not use the first
macro like that and pass a
, b
, and c
as single arguments to the macro. Then you will get what you want.
But there is some hope:
#define UT_HELPER(a,b,c,d) untouchable(a,b,c,d)
#define UT(x, y) UT_HELPER(x, y)
#define first a, b, c
static UT(mrNess, first);
It is similar to the solution found in this stack overflow answer, so I can't claim having thought it up myself.
Note that
#define quote(s) L#@s
doesn't work in my compiler, so I can't fully test it. I simply tried with
#define quote(s) L###s
and that worked.
I hope this gets you going for the real, more complicated macros you seem to have.
When the preprocessor encounters the invocation of a function-like macro, it first identifies the arguments, next completely macro-expands them*, and last replaces the macro invocation with its replacement list, with the expanded arguments inserted at the appropriate places. The expansion of macro first
is (or would be) performed too late for the preprocessor to recognize in the expansion separate arguments to macro untouchable()
. You'll need to find another way.
One possibility is to insert a level of indirection:
#define untouch_wrap(name, args) untouchable(name, args)
static untouch_wrap(mrNess, first);
There, first
is expanded before untouch_wrap
, so that when the result is re-scanned for further macros to replace, the resulting invocation of untouchable()
has the correct number of arguments.
That does rely on the second argument to untouch_wrap()
to expand to a comma-separated list of exactly three members. It would be cleaner and more flexible to define untouch_wrap()
like this:
#define untouch_wrap(name, ...) untouchable(name, __VA_ARGS__)
... but MSVC's handling of variadic macros is non-conforming, and I suspect that it would trip over that.
* Expansion is suppressed for arguments that are operands of the preprocessor's stringification (#
) and token-pasting (##
) operators.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With