【位运算】——根据(mask, vavlue)键值对,生成对应的整数

功能说明

用于根据传入的 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 ,结果就是 0101000080

示例

#include <stdio.h>

#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

解析

BITBIT_MASK_LENBIT_RNGBIT_LOW_BITCOUNT_ARGS 这些前面都单独解析过,参考

MACRO_CHOOSE_HELPER

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_VALCOUNT_ARGS(__VA_ARGS__)

## 对宏参数起作用,那宏直接将 MASK_VALCOUT_ARGS 连接,结果就是 MASK_VALCOUT_ARGS

所以当 MACRO_CHOOSE_HELPER 的级数和 COUT_ARGS 要一致,才能达到宏连接的效果

MACRO_GLUE(x, y) x y

将宏参数 x 和 y 分开,在这里 x 一般为 MASK_VALx,y 为 (__VA_ARGS__)

所以最终的效果就是 MASK_VALx(__VA_ARGS__)

MV(m, v)

设置对应的 mask 值为 v。如果存在多个 mask 位,从第一个置位的 mask 开始

没有设置的 mask 位值为 0

MASK_VALx

MASK_VALx 的 mask 和 value 拆开,分别调用 MV 进行或运算,得到最终的结果。

猜你喜欢

转载自blog.csdn.net/tyustli/article/details/131972394