Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the meaning of this C macro?

Tags:

c

macros

Here is a macro can calculate the count of arguments. and the code like:

#define Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args
#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0

#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n

#define MPL_ARGS_SIZE(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,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))

// the running result ---------------------------------------

MPL_ARGS_SIZE(a,b,c,d,e,f,g)==7

MPL_ARGS_SIZE(a,b,c,d)==4

how to understand

#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0

and

Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX

?

BTW, I know about ##(pound, pound) usage and the mechanism of #define Y_TUPLE_SIZE_I

like image 789
William Sterling Avatar asked Oct 31 '22 11:10

William Sterling


1 Answers

The PREFIX and POSTFIX macros are intended to make it give 0 when no arguments are given, i.e. MPL_ARGS_SIZE(). In this case, Y_TUPLE_SIZE_PREFIX_ and _Y_TUPLE_SIZE_POSTFIX are concatenated to produce Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX, which forces the result to 0.

In the general case, __VA_ARGS__ is non-empty, so the concatenation just expands to the same number of arguments that were given. This is followed by 32, ... 0.

In both cases, the arguments are wrapped in parentheses. Y_TUPLE_SIZE_II strips off these extra parentheses and passes the arguments on to Y_TUPLE_SIZE_I. Y_TUPLE_SIZE_I just expands to its 33rd argument, discarding the rest.

So if you give it 32 arguments, those 32 will be skipped and the number following them, 32, will be the result, as desired. If you give it 31 arguments, it will skip those 31, and the first number that follows, i.e. 32, and the result will be the next number, 31, again as desired.

If you give it a single argument, it will skip that argument and the 31 that follow it, and the result will be 1.

If you give it no arguments, the special case of Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX will come into play, which is 32 empty arguments followed by 0. The 32 empty arguments will be skipped, and the result will be 0.

The reason for the special case for no arguments is that without it, it would behave the same as the one-argument case. The following might help understand it better:

#define Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args
#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n

#define MPL_ARGS_SIZE(...) Y_TUPLE_SIZE_II((__VA_ARGS__,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))

This is the original set of macros, but with all of the special-case handling for zero arguments removed. It works for everything but the zero-argument case, which returns 1 instead of 0.

In order to handle zero arguments, it sandwiches the argumement list between the prefix and postfix macros. If the result expands to Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX, then the argument list was empty, and the special case comes into play.

like image 75
Tom Karzes Avatar answered Nov 09 '22 21:11

Tom Karzes