Variadic macro argument count not working as expected - c++

So, basically I'm trying to implement a macro to count the number of arguments in VA_ARGS.
For the sake of simplicity it only works up to 3 parameters. The problem is that when the macro is used with less than 3 parameters, it doesn't work, and triggers the "expected an expression" error.
#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, PP_RSEQ_N()))
#define PP_ARG_N(_1, _2, _3, N,...) N
#define PP_RSEQ_N() 3,2,1,0
void main()
{
printf("\nTEST PP_NARG: %i", PP_NARG()); //Doesn't work (in this case it shouldn't work, so it's correct)
printf("\nTEST PP_NARG: %i", PP_NARG(0)); //Doesn't work
printf("\nTEST PP_NARG: %i", PP_NARG(0,0)); //Doesn't work
printf("\nTEST PP_NARG: %i", PP_NARG(0,0,0)); //Works
}
Keeping just the line that works it compiles correctly and prints "TEST PP_NARG: 3".
I believe the problem might be that PP_RSEQ_N() is only expanding to "3", instead of "3,2,1,0" for some reason, since even if PP_RSEQ_N() is defined as this
#define PP_RSEQ_N() 10,9,8,7,6,5,4,3,2,1,0
it still doesn't work with less than 3 parameters.
Im using the MSVC compiler and it may be the cause of the problem, since it doesn't behave very well with macros, as seen here: MSVC doesn't expand __VA_ARGS__ correctly

In your implementation PP_RSEQ_N() is an argument to PP_ARG_N. As an argument, it is only expanded in the argument substitution phase of preprocessing, but that only happens just prior to replacing the argument in its replacement list (so long as, in the replacement list, it's not being stringified and is not participating in a paste).
Since PP_ARG_N only has its fourth argument N in its replacement list, PP_RSEQ_N() will only expand if you happen to pass three arguments in. (There is a second scan during the rescan and replacement phase, which applies after argument substitution... but that has no effect here as PP_RSEQ_N() is mentioned in a call).
Get rid of this macro and just put it in the PP_NARG like this:
#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 3,2,1,0))
#define PP_ARG_N(_1, _2, _3, N,...) N
...and things "work" fine:
PP_NARG() expands to 1
PP_NARG(x) expands to 1
PP_NARG(x,y) expands to 2
Note, however, that PP_NARG() doesn't give you 0. Arguably that's actually correct; to the preprocessor, this is not passing zero arguments. It's passing one argument that is just empty. It's the same thing as #define X(A) OPEN A CLOSE/X() yielding OPEN CLOSE. If for some reason you want this to expand to 0, there may be some finagling to get that to happen, but for this answer I'm only focusing on getting you over this one hump.

A PP_ARG_N() implementation which can also distinguish between invocation with and without parameter can be found here (kudos to Scott Morrison). Response for your little program:
TEST PP_NARG: 0
TEST PP_NARG: 1
TEST PP_NARG: 2
TEST PP_NARG: 3

Related

How does expansion of the macro parameters work in c++

I just noticed an interesting thing about the expansion of the macro parameters in C++.
I defined 4 macros; 2 of them turn given parameter into string and another 2 try to separate 2 arguments. I passed them argument with macro which expands into , and got the following results:
#define Quote(x) #x
#define String(x) Quote(x)
#define SeparateImpl(first, second) first + second
#define Separate(pair) SeparateImpl(pair)
#define comma ,
int main(){
Quote(1 comma 2); // -> "1 comma 2"
String(1 comma 2); // -> "1 , 2"
SeparateImpl(1 comma 2); // -> 1 , 2 + *empty arg*
Separate(1 comma 2); // -> 1 , 2 + *empty arg*
return 0;
}
So, as we see macro String turned into "1 , 2", that means macro comma had been unpacked first. However, macro Separate turned into 1 , 2 + **empty arg**, that means macro comma hadn't been unpacked first and I wonder why? I tried this in VS2019.
#define Quote(x) #x
#define String(x) Quote(x)
#define SeparateImpl(first, second) first + second
#define Separate(pair) SeparateImpl(pair)
#define comma ,
Macro invocation proceeds as follows:
Argument substitution (a.s), where if a parameter is mentioned in the replacement list and said parameter does not participate in a paste or stringification, it is fully expanded and said mentions of the parameter in the replacement list are substituted with the result.
Stringification
Pastes
Rescan and further replacement (r.a.f.r.), where the resulting replacement list is rescanned, during which the macro's name is marked as invalid for expansion ("painted blue").
Here's how each case should expand:
Quote(1 comma 2)
a.s. no action (only mention of parameter is stringification). Stringification applies. Result: "1 comma 2".
String(1 comma 2)
a.s. applies; yielding Quote(1 , 2). During r.a.f.r., Quote identified as a macro, but the argument count doesn't match. This is invalid. But see below.
SeparateImpl(1 comma 2)
Invalid macro call. The macro is being invoked with one argument, but it should have 2. Note that comma being defined as a macro is irrelevant; at the level of macro invocation you're just looking at the tokens.
Separate(1 comma 2)
a.s. applies; yielding SeparateImpl(1 , 2). During r.a.f.r., SeparateImpl is invoked... that invocation's a.s. applies, yielding 1 + 2.
I tried this in VS2019.
I could tell from a glance it was VS something before 2020, where the walls tells me they're finally going to work on preprocessor compliance. VS in particular seems to have this strange state in which tokens with commas in them nevertheless are treated as single arguments (it's as if argument identification occurs before expansion but continues to apply or something); so in this case, 1 , 2 would be that strange thing in your String(1 comma 2) call; i.e., Quote is being called with 1 , 2 but in that case it's actually one argument.

How to force additional preprocessor macro scan

I have the following code:
#define FOO_BAR x
#define FOO(x) FOO_BAR
I do want FOO(2) to expand to 2, but I'm getting x instead. I tried to use EXPAND macro to force extra scan:
#define FOO_BAR x
#define EXPAND(x) x
#define FOO(x) EXPAND(FOO_BAR)
Note, this is intentional, that FOO_BAR doesn't accept x as an argument. Basically, I cannot pass x to FOO_BAR.
But it doesn't work as well. Any ideas?
I want this to work on any compiler (MSVC, gcc, clang).
What exactly I am trying to accomplish
My end goal is to create type safe enums for OpenGL. So, I need to do mapping from my safe enum to unsafe ones. So I have something like:
enum class my_enum {
foo,
bar
}
GLenum my_enum2gl(my_enum e) {
switch (e) {
case my_enum::foo: return GL_FOO;
case my_enum::bar: return GL_BAR;
}
return GL_NONE;
}
Since I'm lazy, I did some preprocessor magic. And implemented this as:
#define PP_IMPL_ENUM_VALUE(enum_pair) __PP_EVAL(__PP_IMPL_ENUM_VALUE enum_pair)
#define __PP_IMPL_ENUM_VALUE(cpp_enum, gl_enum) cpp_enum,
#define PP_IMPL_CONVERT(enum_pair) __PP_EVAL(__PP_IMPL_CONVERT enum_pair)
#define __PP_IMPL_CONVERT(cpp_enum, gl_enum) case name::cpp_enum: return gl_enum;
#define DEF_STATE_ENUM(name, ...) \
enum name { \
PP_FOR_EACH(PP_IMPL_ENUM_VALUE, ##__VA_ARGS__) \
}; \
namespace detail { \
GLenum name ## 2gl(name e) { \
switch(e) { \
__PP_EVAL(PP_FOR_EACH(PP_IMPL_CONVERT, ##__VA_ARGS__)) \
default: \
assert(!"Unknown value"); \
return GL_NONE; \
} \
} \
}
DEF_STATE_ENUM(my_enum,
(foo, GL_FOO),
(bar, GL_BAR)
)
The problem is that __PP_IMPL_CONVERT uses name which is not expanded. Passing x to FOO_BAR would mean that I'm passing some extra parameter to a functor for PP_FOR_EACH.
You need to understand
The preprocessor fully expands the arguments to each function-like macro before substituting them into the macro's expansion, except where they are operands of the # or ## preprocessing operators (in which case they are not expanded at all).
After modifying the input preprocessing token sequence by performing a macro expansion, the preprocessor automatically rescans the result for further macro expansions to perform.
In your lead example, then, given
#define FOO_BAR x
#define FOO(x) FOO_BAR
and a macro invocation
FOO(2)
, the preprocessor first macro expands the argument 2, leaving it unchanged, then replaces the macro call with its expansion. Since the expansion does not, in fact, use the argument in the first place, the initial result is
FOO_BAR
The preprocessor then rescans that, recognizes FOO_BAR as the identifier of an object-like macro, and replaces it with its expansion, yielding
x
, as you observed. This is the normal and expected behavior of a conforming C preprocessor, and to the best of my knowledge, C++ has equivalent specifications for its preprocessor.
Inserting an EXPAND() macro call does not help, because the problem is not failure to expand macros, but rather the time and context of macro expansion. Ultimately, it should not be all that surprising that when the replacement text of macro FOO(x) does not use the macro parameter x, the actual argument associated with that parameter has no effect on the result of the expansion.
I cannot fully address your real-world code on account of the fact that it depends centrally on a macro PP_FOR_EACH() whose definition you do not provide. Presumably that macro's name conveys the gist, but as you can see, the details matter. However, if you in fact understand how your PP_FOR_EACH macro actually works, then I bet you could come up with a variant that accepts an additional leading argument, by which you could convey (the same) name to each expansion.
Alternatively, this is the kind of problem for which X Macros were invented. I see that that alternative has already been raised in comments. You might even be able -- with some care -- to build a solution that uses X macros inside, so as to preserve the top-level interface you now have.

How do I combine BOOST_PP_IF with BOOST_PP_LPAREN?

I'm trying to conditionally expand a macro to either "( a" or "b )", but the naive way of doing so doesn't work on either of the compilers I'm using (Microsoft C/C++ and the NDK compiler). Example:
// This works on both compilers, expands to ( a ) as expected
#define PARENS_AND_SUCH BOOST_PP_IF(1, BOOST_PP_LPAREN() a BOOST_PP_RPAREN(), b)
// MSVC: syntax error/unexpected end of file in macro expansion
// NDK: unterminated argument list
#define PARENS_AND_SUCH BOOST_PP_IF(1, BOOST_PP_LPAREN() a, b)
// Desired expansion: ( a
// MSVC expansion: ( a, b )
// NDK: error: macro "BOOST_PP_IIF" requires 3 arguments, but only 2 given
#define PARENS_AND_SUCH BOOST_PP_IF(1, BOOST_PP_LPAREN() a, b BOOST_PP_RPAREN())
What am I doing wrong?
You could force the order of evaluation to conform to the expected one by abstracting out the branches of the IF to subdefinitions, and delay their expansion until the conditional returns a branch:
#define PARENS_AND_SUCH BOOST_PP_CAT(PAS_, BOOST_PP_IF(1, THEN, ELSE))
#define PAS_THEN BOOST_PP_LPAREN() a
#define PAS_ELSE b BOOST_PP_RPAREN()
Since THEN and ELSE aren't complete names, the branches will not be expanded before the IF is expanded; when it returns, the value is combined with PAS_ to form a new valid definition and will expand at that time.
You could also parameterise the THEN and ELSE macros and make this technique more general (and IMO more elegant): passing parameters to an incomplete name essentially forms a thunk, and works pretty much the same way (the incomplete function-like macro name will be passed around plus parameter list until it's completed).

Use macro in C++

First - sorry for my bad English :-(
Second - I have some intresting task.
Preface.
Programm will be work on ATMega162. We use macro, becouse functions work very slowly. Even inline...
Task.
I have a macro:
#define ProvSetBit(reg, bit) (((reg) & (1<<(bit))) != 0)
and check bits turn in very long, unreadable string:
ProvSetBit(SystemStatus[0], COMMAND_ON_DF);
and #define COMMAND_ON_DF 0u
I want to modificate it in:
ProvSetBit(COMMAND_ON_DF);
where COMMAND_ON_DF:
#define COMMAND_ON_DF (SystemStatus[0], 0u)
or something there. But it don't work. Debugger write:"Error[Pe054]: too few arguments in macro invocation". What you can advice me?
If a function is actually inlined, it cannot be slower than a macro doing the same thing - they lead to identical assembly. And a function as trivial as the code you posted is pretty much guaranteed to be inlined. You should ditch the macro and instead investigate why the compiler is not doing inlining for you - perhpas you're not passing the proper compilation flags?
If you reall, really want/have to stick with macros for this one, you can use Boost.Preprocessor to achieve this:
#include "boost/preprocessor/facilities/expand.hpp"
#define ProvSetBit(args) BOOST_PP_EXPAND(ProvSetBit_1 args)
#define ProvSetBit_1(reg, bit) (((reg) & (1<<(bit))) != 0)
#define COMMAND_ON_DF (SystemStatus[0], 0u)
int main()
{
ProvSetBit(COMMAND_ON_DF);
}
Live example

How to expand this macro properly?

When I define this macro:
#define SQR(x) x*x
Let's say this expression:
SQR(a+b)
This expression will be replaced by the macro and looks like:
a+b*a+b
But, if I put a ++ operator before the expression:
++SQR(a+b)
What the expression looks like now? Is this ++ placed befor every part of SQR paramete? Like this:
++a+b*++a+b
Here I give a simple program:
#define SQR(x) x*x
int a, k = 3;
a = SQR(k+1) // 7
a = ++SQR(k+1) //9
When defining macros, you basically always want to put the macro parameters in parens to prevent the kind of weird behaviour in your first example, and put the result in parens so it can be safely used without side-effects. Using
#define SQR(x) ((x)*(x))
makes SQR(a+b) expand to ((a+b)*(a+b)) which would be mathematically correct (unlike a+b*a+b, which is equal to ab+a+b).
Putting things before or after a macro won't enter the macro. So ++SQR(x) becomes ++x*x in your example.
Note the following:
int a=3, b=1;
SQR(a+b) // ==> a+b*a+b = 3+1*3+1 = 7
++SQR(a+b) // ==> ++a+b*a+b ==> 4 + 1*4 + 1 = 9
// since preincrement will affect the value of a before it is read.
You're seeing the ++SQR(a+b) appear to increment by 2 since the preincrement kicks in before a i read either time, i.e. a increments, then is used twice and so the result is 2 higher than expected.
NOTE As #JonathanLeffler points out, the latter call invokes undefined behaviour; the evaluation is not guaranteed to happen left-to-right. It might produce different results on different compilers/OSes, and thus should never be relied on.
For C++ the right way to define this macro is to not use a macro, but instead use:
template<typename T> static T SQR( T a ) { return a*a; }
This will get right some horrible cases that the macro gets wrong:
For example:
SQR(++a);
with the function form ++a will be evaluated once. In the macro form you get undefined behaviour as you modify and read a value multiple times between sequence points (at least for C++)
A macro definition just replaces the code,hence it is generally preferable to put into parenthesis otherwise the code may replaced in a way you don't want.
Hence if you define it as :
#define SQR(x) ((x)*(x))
then
++SQR(a+b) = ++((a+b)*(a+b))
In your example, ++SQR(a+b) should be expanded as ++a+b*a+b.
So, if a == 3 and b == 1 you will get the answer 9 if the compiler evaluates it from left to right.
But your statement ++SQR(3+1) is not correct because it will be expanded as ++3+1*3+1 where ++3 is invalid.
In your preprocessor it evaluates to ++a+b*a+b. The right way is put brackets around each term and around the whole thing, like:
#define SQR(x) ((x)*(x))