这个C宏的含义是什么?

5

这里有一个宏可以计算参数的数量,代码如下:

#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

如何理解 IT 技术相关内容?
#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0

并且

Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX

BTW,我知道##(井号、井号)的用法和#define Y_TUPLE_SIZE_I的机制。


1
那是一组相当疯狂的宏... - user253751
你只是在组成一堆空参数来传递(和0)。当你把它们连接起来,就得到了一个参数列表。虽然如此,这似乎比参数计数宏所需的要多一点。我猜你所询问的宏可能处理了MPL_ARGS_SIZE()的情况,以便给出0而不是1。 - chris
@chris 不,只有在没有给出参数的情况下,空参数才会发挥作用。这是一个特殊情况。在正常情况下,不存在空参数。 - Tom Karzes
@TomKarzes,这就是我在最后一句话中所说的。评论在构建越来越多的心理模型时有点结构化。 - chris
我在下面扩展了我的答案,包括一个简化的解决方案,不包括零参数的特殊情况(因此对于该情况结果为1而不是0)。这应该更容易理解。 - Tom Karzes
1个回答

2
PREFIX和POSTFIX宏旨在在不给定参数时使其返回0,即MPL_ARGS_SIZE()。在这种情况下,将Y_TUPLE_SIZE_PREFIX_和_Y_TUPLE_SIZE_POSTFIX连接起来生成Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX,从而强制结果为0。
在一般情况下,__VA_ARGS__不为空,因此连接只会扩展为给定的相同数量的参数。然后是32、... 0。
在两种情况下,参数都被包裹在括号中。Y_TUPLE_SIZE_II去掉这些额外的括号,并将参数传递给Y_TUPLE_SIZE_I。Y_TUPLE_SIZE_I仅扩展为其第33个参数,丢弃其余部分。
因此,如果您提供32个参数,这32个参数将被跳过,后面的数字32将是结果,正如所需的那样。如果您提供31个参数,它将跳过这31个参数,以及随后的第一个数字,即32,结果将是下一个数字,即31,同样符合要求。
如果您提供单个参数,它将跳过该参数和随后的31个参数,结果将为1。
如果您没有提供参数,则会出现特殊情况Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX,其中有32个空参数,后跟0。这32个空参数将被跳过,结果将为0。
没有参数的特殊情况的原因是,如果没有它,它将与单参数情况相同。以下内容可能有助于更好地理解:
#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))

这是原始的宏集,但已删除所有针对零参数的特殊处理。它适用于除零参数情况外的所有情况,后者返回1而不是0。

为了处理零参数,它在前缀和后缀宏之间夹着参数列表。如果结果扩展为Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX,则参数列表为空,并且特殊情况发挥作用。


方法Y_TUPLE_SIZE_II((__VA_ARGS__,32...0))更易理解。但是回到#define MPL_ARGS_SIZE(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,...),例如如果参数是a、b、c,那么当展开MPL_ARGS_SIZE(a, b, c)时会发生什么呢? 似乎应该是Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_a,b,c_Y_TUPLE_SIZE_POSTFIX, ...0)),当然这是错误的陈述,如何理解它呢? - William Sterling
在有一个或多个参数的情况下,第一个和最后一个参数会被前缀和后缀字符串所改变,但这并不重要,因为参数的唯一目的是占据一个参数位置。它们在最终结果中都被丢弃了。 - Tom Karzes
哎呀,我之前迷路了... Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_a,b,c_Y_TUPLE_SIZE_POSTFIX, ...0) 将会被展开为 Y_TUPLE_SIZE_I(Y_TUPLE_SIZE_PREFIX_a,b,c_Y_TUPLE_SIZE_POSTFIX, ...0),其中 PREFIX_a、b、c_POSTFIX 都作为 Y_TUPLE_SIZE_I 宏的参数。谢谢。 - William Sterling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接