Bit operation–Generate the corresponding integer according to the (mask, vavlue) key-value pair

Article directory

    • Function Description
    • example
    • analyze
      • MACRO_CHOOSE_HELPER
      • MACRO_GLUE(x, y) x y
      • MV(m, v)
      • MASK_VALx

Function description

It is used to generate an integer according to the incoming mask and the corresponding value, and the unspecified mask bit is cleared.

  • MASK_VAL(BIT(1), 1), set bit1 to 1, the result is 2.
  • MASK_VAL(BIT(1), 1, BIT(2), 1), set bit1 to 1, bit2 to 1, the result is 4.
  • MASK_VAL(BIT(3), 0, BIT(4), 1, BIT_RNG(5, 6), 2), bit3 is cleared to 0, bit4 is set to 1, and the value of bit[5:6] is 2, the result is 01010000 which is 80.

Example

#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) & amp;BIT(0)) ? 0 : (((y) & amp;BIT(1)) ? 1 : (((y) & amp;BIT(2) ) ? 2 : (((y) & amp;BIT(3)) ? 3 : \
                            (((y) & amp;BIT(4)) ? 4 : (((y) & amp;BIT(5)) ? 5 : (((y) & amp;BIT(6)) ? 6 : (( (y) & BIT(7)) ? 7 : \
                            (((y) & amp;BIT(8)) ? 8 : (((y) & amp;BIT(9)) ? 9 : (((y) & amp;BIT(10)) ? 10 : (( (y) & BIT(11)) ? 11 : \
                            (((y) & amp;BIT(12)) ? 12 : (((y) & amp;BIT(13)) ? 13 : (((y) & amp;BIT(14)) ? 14 : (( (y) & BIT(15)) ? 15 : \
                            (((y) & amp;BIT(16)) ? 16 : (((y) & amp;BIT(17)) ? 17 : (((y) & amp;BIT(18)) ? 18 : (( (y) & BIT(19)) ? 19 : \
                            (((y) & amp;BIT(20)) ? 20 : (((y) & amp;BIT(21)) ? 21 : (((y) & amp;BIT(22)) ? 22 : (( (y) & BIT(23)) ? 23 : \
                            (((y) & amp;BIT(24)) ? 24 : (((y) & amp;BIT(25)) ? 25 : (((y) & amp;BIT(26)) ? 26 : (( (y) & BIT(27)) ? 27 : \
                            (((y) & amp;BIT(28)) ? 28 : (((y) & amp;BIT(29)) ? 29 : (((y) & amp;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) & amp; BIT(5) bit5 cleared \

 * 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\
", count0);
    printf("count1 = %d\
", count1);
    printf("count2 = %d\
", count2);
    printf("count3 = %d\
", count3);
    printf("count4 = %d\
", count4);
    printf("count5 = %d\
", count5);
    printf("count6 = %d\
", count6);

    return 0;
}

result print

count0 = 2
count1 = 4
count2 = 6
count3 = 0
count4 = 16
count5 = 80
count6 = 8

Analysis

BIT, BIT_MASK_LEN, BIT_RNG, BIT_LOW_BIT, COUNT_ARGS have been parsed separately ,refer to

  • preprocessing
  • bit manipulation

MACRO_CHOOSE_HELPER

MACRO_CHOOSE_HELPER Why does the macro connection use two levels instead of directly

MACRO_CHOOSE_HELPER(base, cout) base##cout

When directly MACRO_CHOOSE_HELPER(base, cout) base##cout, MASK_VAL, COUNT_ARGS(__VA_ARGS__)) passes in MASK_VAL and COUNT_ARGS(__VA_ARGS__)

And ## works on macro parameters, then the macro directly connects MASK_VAL and COUT_ARGS, and the result is MASK_VALCOUT_ARGS

So when the series of MACRO_CHOOSE_HELPER is consistent with COUT_ARGS, the effect of macro connection can be achieved

MACRO_GLUE(x, y) x y

Separate macro arguments x and y, where x is typically MASK_VALx and y is (__VA_ARGS__)

So the final effect is MASK_VALx(__VA_ARGS__)

MV(m, v)

Set the corresponding mask value to v. If there are multiple mask bits, start with the first set mask

Mask bits that are not set have a value of 0

MASK_VALx

Separate the mask and value of MASK_VALx, and call MV to perform OR operation to get the final result.