C语言对寄存器的位操作

C语言位操作

1、位操作符

(1)位与& 逻辑与&& 1&1=1 1&0=0 0&0=0 0&1=0

(2)位或 | 逻辑或 || 1 | 1=1 1 | 0=1 0 | 0=0 0 | 1=1

(3)位取反~ 逻辑取反 !

(4)位异或 ^ 不同为1,相同为0 1^1=0 1^0=1 0^0=0 0^1=1

总结:

  • 位操作是按照二进制数的每一位进行操作的,逻辑操作是对数的整体操作的
  • 位与,与1位与无变化,与0位与为0
  • 位或,与1位或为1,与0位或无变化
  • 位异或,与1位异或会取反,与0位异或无变化

(5)移位操作

  • C语言的移位要取决于数据类型

  • 左移位 << 右移位 >>

    • 无符号数, 逻辑移位

      左移位时右侧补0

      右移位时左侧补0

    • 有符号数, 算数移位

      左移位时右侧补0(相当于逻辑移位)

      右移位时左侧补符号位,如果是正数就补0,负数就补1(第一位为符号位,0为正,1为负)

2、位操作符在操作寄存器时的特殊作用

(1)寄存器的操作要求

  • ARM是内存和IO统一编址的,CPU通过向内部外设的寄存器写入特定值来操作内部外设
    • 寄存器特点:按位进行规划和使用、读写是32位整体进行操作的
  • 寄存器的操作要求:操作寄存器时,要求改变某一特定位,而不影响其他位
  • 如何实现:读出—>改相应位—>写入

(2)改相应位的操作

​ 基本思路:寄存器特定位改变而不影响其他位,构造合适的1和0组成的数和这个寄存器原来的值位与、位或、位取反

  • 特定位清零用 & (用0清零)

    • 与1位与无变化、与0位与变为0

    • 要清零的位为0,其他位为1,然后这个数与原数位与

    • 举例:原32位寄存器的值位0xAAAAAAAA,对bit2~bit8清零

      ​ 0xAAAAAAAA & 0xFFFFFE03

  • 特定位置1用 | (用1置1)

    • 与1位或为1,与0位或无变化

    • 要置1的位为1,其他位为0,然后这个数与原数位或

    • 举例:原32位寄存器的值位0xAAAAAAAA,对bit8~bit15置1

      ​ 0xAAAAAAAA | 0x0000FF00

  • 特定位取反用^ (用1取反)

    • 与1位异或为会取反,与0位异或无变化

    • 要取反的位为1,其他位为0,然后这个数与原数位异或

    • 举例:原32位寄存器的值位0xAAAAAAAA,对bit8~bit15取反

      ​ 0xAAAAAAAA ^ 0x0000FF00

  • 代码举例

    unsigned int a = 0xa12aaaa7;
    unsigned int b = 0xFFFF00FF;
    unsigned int c;
    c = a & b;
    // 16进制数的打印
    printf("a & b = %#X.\n", c);
    printf("a & b = 0x%x.\n", c);
    

3、使用位运算构建特殊二进制数

(1)使用位移获取特定位为1的二进制数

  • 获取bit3-bit7为1,同时bit23-bit25为1,其余都为0的数
    • (0x1F<<3) | (0x7<<23)

(2)使用位移获取特定位为0的二进制数

  • 获取bit4-bit10为0,其余都为1的数
    • bit4-bit10为0也就是bit0-bit3为1同时bit11-bit31为1
      (0xF<<0) | (0x1FFFFF<<11)
    • ~(0x7F<<4)

(3)总结

  • 1少0多,连续多个1左移n位
  • 0少1多,先构建其位反数,再按位取反
  • 连续1(0)不止一个,则通过分段分别构建,再彼此位与即可

4、位运算的操作实战

​ 回顾:清零用&,置1用 | ,取反用^

​ ~和<< >>用来构建特定二进制数

unsigned int a ; // 定义无符号数,如果是有符号数,那么位移就会出问题

(1)给定一个整型数a,设置a的bit3,保证其他位不变

  • a |= (0x1<<3)

(2)给定一个整型数a,设置a的bit3-bit7,保证其他位不变

  • a |= (0x1F<<3) a |= (0b11111<<3)

(3)给定一个整型数a,清除a的bit15,保证其他位不变

  • a &= (~(0x1<<15)) a = (a | (0x7FFF<<0) | (a | (0xFFFF<<16) (不采用)

(4)给定一个整型数a,清除a的bit15-bit23,保证其他位不变

  • a &= (~(0x1FF<<15))

(5)给定一个整型数a,取出a的bit3-bit8

  • 先将a的bit3-bit8不变,其余位清零
    • a &= (0x3F<<3)
  • 再将a右移3位
    • a >>= 3

(6)给寄存器的bit7-bit17赋值937,其余位不受影响

  • 先将bit7-bit17全部清零,其他位不变
    • a &= (~(0x7FF<<7))
  • 再将937写入bit7-bit17,其他位不变
    • a |= (937<<7)

(7)将寄存器bit7-bit17中的值加17,其余位不受影响

  • 先读出bit7-bit17的值
    • temp = a & (0x7FF<<7)
    • temp >>= 7;
  • 给temp加17
    • temp += 17
  • 将bit7-bit17清零
    • a &= (~(0x7FF<<7))
  • 将temp算出的值写入到bit7-bit17
    • a |= (temp<<7)

(8)给寄存器bit7-bit17赋值937,同时给bit21-bit25赋值17

  • 先将bit7-bit17和bit21-bit25清零,其他位不变
    • a &= (~ ( (0x7ff<<7) | (0x1f<<21) ) ) // 位或优先级高于~
  • 再将937赋值到bit7-bit17,17赋值到bit21-bit25
    • a |= ((937<<7) | (17<<21))

printf(“a = %u.\n”, a); // %u 打印无符号数

5、技术升级:使用宏定义来完成运算

(1)直接用宏定义来置位、复位(最右边是第一位,bit0)

// 置位
#define SET_NTH_BIT(x, n)	(x | ( (1U) << (n-1) )  )
// 复位
#define CLEAR_NTH_BIT(x, n)	(x & ~ ( (1U) << (n-1) )  )
// 1后边的U表示这个数字是无符号数(有符号数的右移是会出问题的)

(2)将32位数x的第n位到第m位置位

// 关键点:我们需要一个算式来得到(m-n+1)个1的十六进制数
// 第1步,先得到32个1: ~0U	(~按位取反得到32个1,如果直接1U那么就只有bit0位1)
// 第2步,将得到的数右移x位即可得到(m-n+1)个: (~0U) >> (32-(m-n+1)) 或 ~(~0U<<(m-n+1))
#define SET_BIT_N_M(x, n, m)	(x | (((~0U) >> (32-(m-n+1))) << (n-1)))
#define SET_BIT_N_M(x, n, m)	(x | ~(~0U<<(m-n+1))<<(n-1))

(3)截取变量的部分连续位(相当于4中的(5))

// 给定一个整型数a,取出a的bit3-bit8
//   先将a的bit3-bit8不变,其余位清零	    a &= (0x3F<<3)
//   再将a右移3位					   a >>= 3
#define GETBITS(x, n, m)	(x & ~(~0U << (m-n+1)) << (n-1)) >> (n-1))
// 思路:
// 	先将x的bit(n-1)-bit(m-1)不变,其余位清零
//		得到(m-n+1)个1的十六进制数    ~(~0U << (m-n+1))                (得到0x3F)
//		将得到的16进制数左移(n-1)     ~(~0U << (m-n+1)) << (n-1)       (得到0x3F<<3)
// 		x和左移后的数位与             x & ~(~0U << (m-n+1)) << (n-1)   (a &= (0x3F<<3))
// 	再将x右移(n-1)位
// 		位与后的数右移(n-1)		  (x & ~(~0U << (m-n+1)) << (n-1)) >> (n-1)
// 最终结果
#define GETBITS(x, n, m)	(x & ~(~0U << (m-n+1)) << (n-1)) >> (n-1))
// 得到(m-n+1)个1的十六进制数的两种方式:
// 		32位的1先左移(m-n+1)位,那么低(m-n+1)位位0,高(32-(m-n+1))位为1,再将其按位取反,
// 						   就得到低(m-n+1)位为1,高(32-(m-n+1))位为0。
				~(~0U << (m-n+1))
// 		有(m-n+1)个1,那么就有32-(m-n+1)个0,将32位的1先右移32-(m-n+1),
// 							那么高32-(m-n+1)位为0,低(m-n+1)位为1。
				(~0U) >> (32-(m-n+1))
  • 15
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值