用于根据传入的 mask 和对应的值,生成整数,未指定的 mask 位清零。
MASK_VAL(BIT(1), 1)
,bit1 置 1,结果就是 2。MASK_VAL(BIT(1), 1, BIT(2), 1)
,bit1 置 1, bit2 置 1, 结果就是 4。MASK_VAL(BIT(3), 0, BIT(4), 1, BIT_RNG(5, 6), 2)
,bit3 清 0,bit4 置 1,bit[5:6] 的值为 2 ,结果就是 01010000
即 80
。#include
#define BIT(n) (1 << (n))
#define BIT_MASK_LEN(len) (BIT(len)-1)
#define BIT_RNG(s, e) (BIT_MASK_LEN((e) - (s) + 1) << (s))
/* return the bit index of the lowest 1 in y. ex: 0b00110111000 --> 3 */
#define BIT_LOW_BIT(y) (((y)&BIT(0)) ? 0 : (((y)&BIT(1)) ? 1 : (((y)&BIT(2)) ? 2 : (((y)&BIT(3)) ? 3 : \
(((y)&BIT(4)) ? 4 : (((y)&BIT(5)) ? 5 : (((y)&BIT(6)) ? 6 : (((y)&BIT(7)) ? 7 : \
(((y)&BIT(8)) ? 8 : (((y)&BIT(9)) ? 9 : (((y)&BIT(10)) ? 10 : (((y)&BIT(11)) ? 11 : \
(((y)&BIT(12)) ? 12 : (((y)&BIT(13)) ? 13 : (((y)&BIT(14)) ? 14 : (((y)&BIT(15)) ? 15 : \
(((y)&BIT(16)) ? 16 : (((y)&BIT(17)) ? 17 : (((y)&BIT(18)) ? 18 : (((y)&BIT(19)) ? 19 : \
(((y)&BIT(20)) ? 20 : (((y)&BIT(21)) ? 21 : (((y)&BIT(22)) ? 22 : (((y)&BIT(23)) ? 23 : \
(((y)&BIT(24)) ? 24 : (((y)&BIT(25)) ? 25 : (((y)&BIT(26)) ? 26 : (((y)&BIT(27)) ? 27 : \
(((y)&BIT(28)) ? 28 : (((y)&BIT(29)) ? 29 : (((y)&BIT(30)) ? 30 : (((y)&BIT(31)) ? 31 : 32 \
))))))))))))))))))))))))))))))))
/* get macro args numbers: COUNT_ARGS(1, 4, 6) -> 3 */
#define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...) N
#define COUNT_ARGS(...) __COUNT_ARGS(, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
/* macro connect: MASK_VAL2, MASK_VAL2 */
#define __MACRO_CHOOSE_HELPER(base, count) base##count
#define MACRO_CHOOSE_HELPER(base, count) __MACRO_CHOOSE_HELPER(base, count)
/* macro expend: MACRO_GLUE(MASK_VAL2, (xxx)) -> MASK_VAL2(xxx)*/
#define MACRO_GLUE(x, y) x y
/* get MASK_VALx data */
#define VARARG(base, ...) MACRO_GLUE(MACRO_CHOOSE_HELPER(base, COUNT_ARGS(__VA_ARGS__)), (__VA_ARGS__))
/**
* @brief set mask value: MV(5, 0) -> (0 << 5) & BIT(5) bit5 cleared \n
* support BIT_RNG()
*/
#define MV(m, v) (((v) << BIT_LOW_BIT(m)) & (m))
#define MASK_VAL2(m, v) (MV(m, v))
#define MASK_VAL4(m1, v1, m2, v2) (MV(m1, v1) | MV(m2, v2))
#define MASK_VAL6(m1, v1, m2, v2, m3, v3) (MV(m1, v1) | MV(m2, v2) | MV(m3, v3))
#define MASK_VAL8(m1, v1, m2, v2, m3, v3, m4, v4) (MV(m1, v1) | MV(m2, v2) | MV(m3, v3) | MV(m4, v4))
#define MASK_VAL10(m1, v1, m2, v2, m3, v3, m4, v4, m5, v5) (MV(m1, v1) | MV(m2, v2) | MV(m3, v3) | MV(m4, v4) | MV(m5, v5))
#define MASK_VAL12(m1, v1, m2, v2, m3, v3, m4, v4, m5, v5, m6, v6) (MV(m1, v1) | MV(m2, v2) | MV(m3, v3) | MV(m4, v4) | MV(m5, v5) | MV(m6, v6))
#define MASK_VAL14(m1, v1, m2, v2, m3, v3, m4, v4, m5, v5, m6, v6, m7, v7) (MV(m1, v1) | MV(m2, v2) | MV(m3, v3) | MV(m4, v4) | MV(m5, v5) | MV(m6, v6) | MV(m7, v7))
#define MASK_VAL16(m1, v1, m2, v2, m3, v3, m4, v4, m5, v5, m6, v6, m7, v7, m8, v8) (MV(m1, v1) | MV(m2, v2) | MV(m3, v3) | MV(m4, v4) | MV(m5, v5) | MV(m6, v6) | MV(m7, v7) | MV(m8, v8))
/**
* @brief generate a mask value of up to 8 bits
*/
#define MASK_VAL(...) VARARG(MASK_VAL, __VA_ARGS__)
int main(int argc, char *argv[])
{
int count0 = MASK_VAL(BIT(1), 1); /* 0010 */
int count1 = MASK_VAL(BIT(1), 0, BIT(2), 1); /* 0100 */
int count2 = MASK_VAL(BIT(1), 1, BIT(2), 1); /* 0110 */
int count3 = MASK_VAL(BIT(1), 0, BIT(2), 0); /* 0000 */
int count4 = MASK_VAL(BIT(3), 0, BIT(4), 1); /* 10000 */
int count5 = MASK_VAL(BIT(3), 0, BIT(4), 1, BIT_RNG(5, 6), 2); /* 01010000 */
int count6 = MASK_VAL(BIT(3), 1, BIT(4), 0); /* 1000 */
printf("count0 = %d\n", count0);
printf("count1 = %d\n", count1);
printf("count2 = %d\n", count2);
printf("count3 = %d\n", count3);
printf("count4 = %d\n", count4);
printf("count5 = %d\n", count5);
printf("count6 = %d\n", count6);
return 0;
}
结果打印
count0 = 2
count1 = 4
count2 = 6
count3 = 0
count4 = 16
count5 = 80
count6 = 8
BIT
,BIT_MASK_LEN
,BIT_RNG
,BIT_LOW_BIT
,COUNT_ARGS
这些前面都单独解析过,参考
MACRO_CHOOSE_HELPER
宏连接为什么使用两级,而不直接用
MACRO_CHOOSE_HELPER(base, cout) base##cout
当直接 MACRO_CHOOSE_HELPER(base, cout) base##cout
时候,MACRO_CHOOSE_HELPER(MASK_VAL, COUNT_ARGS(__VA_ARGS__))
传入的是 MASK_VAL
和 COUNT_ARGS(__VA_ARGS__)
而 ##
对宏参数起作用,那宏直接将 MASK_VAL
和 COUT_ARGS
连接,结果就是 MASK_VALCOUT_ARGS
所以当 MACRO_CHOOSE_HELPER
的级数和 COUT_ARGS
要一致,才能达到宏连接的效果
将宏参数 x 和 y 分开,在这里 x 一般为 MASK_VALx
,y 为 (__VA_ARGS__)
所以最终的效果就是 MASK_VALx(__VA_ARGS__)
设置对应的 mask 值为 v。如果存在多个 mask 位,从第一个置位的 mask 开始
没有设置的 mask 位值为 0
将 MASK_VALx
的 mask 和 value 拆开,分别调用 MV
进行或运算,得到最终的结果。