【C语言】宏定义实现位运算

一、常用位操作符

1.1 位与&

真值表

& 1 0
1 1 0
0 0 0

特点

有0为0,全1为1

1.2 位或|

真值表

| 1 0
1 1 1
0 1 0

特点

有1为1,全0为0

1.3 位异或^

真值表

^ 1 0
1 0 1
0 1 0

特点

相同为0,相异为1

1.4 位取反~

位取反是将操作数的二进制为逐个按位取反,注意与逻辑取反区分

1.5 左位移<<与右位移>>

C语言的位移运算要取决于其数据类型

无符号数

  • 左移时右侧补零,为逻辑位移
  • 右移时左侧补零,为逻辑位移

有符号数

  • 左移时右侧补零,为算术位移(相当于逻辑位移)
  • 右移时左侧补符号位(正数补0负数补1),为算术位移

二、位运算构建特定二进制数

2.1 理论基础

2.1.1 位与、位或、位异或的运算特点

  • 任何位与1位与无变化,与0位与变成0
  • 任何位与1位或变成1,与0位或无变化
  • 任何位与1位异或取反,与0位异或无变化

所以有:

  • 特定位复位0:与0&
  • 特定位置位1:与1|
  • 特定位取反 :与1^

2.1.2 位移结合位取反构建特定二进制数

构建特定位为1的二进制数

(1)bit3~bit71,其他位为0的二进制数

    size_t ua = 0X1F << 3;
  1. 0X1F说明这部分有5位,分别为bit0~bit4
  2. 左移3说明这5位变成了bit3 ~ bit7

(2)bit3~bit71bit23~bit251,其余位为0

    size_t ua = 0X1F << 3 | 0X07 << 23;
构建特定位为0的二进制数

先构建特定位为1的二进制数,再进行位取反即可

bit3~bit70bit23~bit250,其余位为1

    size_t ua = ~ (0X1F << 3 | 0X07 << 23);

2.2 经典操作

先看明白2.1中的理论基础再看这个!!!

2.2.1 置位特定位

(1)给定一个无符整型数ua,置位uabit3,保证其他位不变

    ua |= (0X01 << 3);

(2)给定一个无符整型数ua,置位uabit3~bit7,保证其他位不变

    ua |= (0X1F << 3);

2.2.2 复位特定位

(1)给定一个无符整型数ua,复位uabit15,保证其他位不变

    ua &= ~(0X01 << 15);

(2)给定一个无符整型数ua,复位uabit15~bit23,保证其他位不变

    ua |= (0X1FF << 15);

2.2.3 取出特定位

给定一个无符整型数ua,置位取出uabit3~bit7,存放在ub

  1. 先让特定位保持不变,其他位全部复位
  2. 再右移3位得到结果
    size_t ub = ua;
    ub &= (0X1F << 3);
    ub >>= 3;

2.2.4 给特定位进行赋值/加减运算

(1)给寄存器的bit7~bit20赋值845,其余位不受影响

  1. 先将特定位全部清零
  2. 再进行赋值
    ua &= ~(0X3FFF << 7);
    ua |= (845 << 7);

(2)给寄存器的bit7~bit20赋值845,同时给bit23~bit28赋值548,其余位不受影响

    ua &= ~ ((0X3FFF << 7) | (0X3F << 23));
    ua |= ((845 << 7) | (548 << 23));

(3)将寄存器bit7~bit20中的值加上20,其余位不受影响

  1. 先读出特定位的值
  2. 给读出的值加上特定数
  3. 将特定位清零
  4. 对特定位进行赋值
    size_t ub = ua;
    ub &= (0X3FFF << 7);
    ub >>= 7;
    ub += 20;
    ua &= ~ (0X3FFF << 7);
    ua |= (ub << 7);

三、宏定义完成位操作

3.1 单独某一位置位

ua的第bit_number + 1位置位(第1位对应bit0,下同)

#define SET_BIT_NUMBER(UA, BIT_NUMBER)  (\
UA | ((typeof (UA))1U << BIT_NUMBER))

3.2 单独某一位复位

ua的第bit_number + 1位复位

#define RESET_BIT_NUMBER(UA, BIT_NUMBER)(\
UA & ~ ((typeof (UA))1U << BIT_NUMBER))

3.3 连续位置位

要求

uabit_m + 1位到bit_n + 1位置位

思路分析

首先需要N = bit_n - bit_m + 1个1

  1. 得到一个全1的数:~ (0U)
  2. 左移N位得到N个0:~ (0U) << N
  3. 再进行取反即得到N个1:~ (~ (0U) << N)

再左移bit_m位再与原数位或运算即可

参考代码段

#define SET_BITS_M_N(UA, BIT_M, BIT_N)  (\
UA | (~ (~ ((typeof (UA))0U) << (\
BIT_N - BIT_M + 1)) << BIT_M))

3.4 连续位复位

要求

uabit_m + 1位到bit_n + 1位复位

思路分析

这个和置位差不多,只是最后一步运算不同而已

代码段

#define RESET_BITS_M_N(UA, BIT_M, BIT_N)(\
UA & ~ (~ (~ ((typeof (UA))0U) << (\
BIT_N - BIT_M + 1)) << BIT_M))

3.5 截取部分连续位

要求

uabit_m + 1位到bit_n + 1位取出

思路分析

先将其他位复位,再右移即可

  1. 和3.3一样先得到N个1:
    ~ (~ (0U) << N)
  2. 左移bit_m位并与ua相与
    UA & ~ (~ (0U) << N) << BIT_M
  3. 再右移即可

参考代码段

#define GETBITS_N_M(UA, BIT_M, BIT_N)   (\
(UA & ~ (~ ((typeof (UA))0U) << (\
BIT_N - BIT_M + 1)) << BIT_M) >> BIT_M)

3.5 测试代码

#include 

#define SET_BIT_NUMBER(UA, BIT_NUMBER)  (\
UA | ((typeof (UA))1U << BIT_NUMBER))

#define RESET_BIT_NUMBER(UA, BIT_NUMBER)(\
UA & ~ ((typeof (UA))1U << BIT_NUMBER))

#define SET_BITS_M_N(UA, BIT_M, BIT_N)  (\
UA | (~ (~ ((typeof (UA))0U) << (\
BIT_N - BIT_M + 1)) << BIT_M))

#define RESET_BITS_M_N(UA, BIT_M, BIT_N)(\
UA & ~ (~ (~ ((typeof (UA))0U) << (\
BIT_N - BIT_M + 1)) << BIT_M))

#define GETBITS_N_M(UA, BIT_M, BIT_N)   (\
(UA & ~ (~ ((typeof (UA))0U) << (\
BIT_N - BIT_M + 1)) << BIT_M) >> BIT_M)

int main(void)
{
    size_t UA = 0XF000F000;

    printf("0X%lX\n", SET_BIT_NUMBER(UA, 3) | SET_BIT_NUMBER(UA, 4));
    printf("0X%lX\n", RESET_BIT_NUMBER(UA, 3) | RESET_BIT_NUMBER(UA, 4));
    printf("0X%lX\n", SET_BITS_M_N(UA, 0, 3) | SET_BITS_M_N(UA, 4, 7));
    printf("0X%lX\n", RESET_BITS_M_N(UA, 12, 15) | RESET_BITS_M_N(UA, 28, 33));
    printf("0X%lX\n", GETBITS_N_M(UA, 0, 15));

    return 0;
}

测试结果及分析

bit3bit4进行置位如图所示:
【C语言】宏定义实现位运算_第1张图片
bit0~3bit4~7进行置位如图所示:
【C语言】宏定义实现位运算_第2张图片
我们可以看到程序的运行结果和上述分析结果是一致的
【C语言】宏定义实现位运算_第3张图片

你可能感兴趣的:(C语言)