美文网首页
C语言基础之位运算(二)

C语言基础之位运算(二)

作者: Eugene_iOS | 来源:发表于2023-04-01 16:42 被阅读0次

C语言基础之位运算(一)
C语言基础之位运算(二)
C语言基础之位运算(三)

1.寄存器的读写

  • ARM中内存与IO是统一编址的,ARM中有很多内部外设,Soc中CPU通过这些外设的寄存器写入一些特定的值来操控这个内部外设,进而操控硬件设备动作。即读、写寄存器就是操控硬件。
  • 寄存器的特点是:按位进行规划和使用,读、写是32位整体进行操作的;
  • 寄存器读写的要求:在改变特定位时,不可改变和影响其他位;
  • 变更寄存器中特定值的步骤:--

:要变更寄存器中某些特定位,先读取寄存器中整体原来的值;
:修改读取的整体原来值中的某些特定位;
:将修改过特定位的整体,统一写入寄存器;

  • 注意:读取一次寄存器的值是32位的,不论修改几位特定值,都必须整体读出32位的内容,在不影响其他原来位值的情况下,将目标特定位进行修改,然后统一写入寄存器;

2.寄存器的读写方式

使用C语言对寄存器赋值时,常常需要用到C语言的位操作符。常用的操作手法有以下几种:

2.1、把寄存器某位清零 &

若希望寄存器中某些特定位变成0,而不影响其他位,可以构造一个合适的二进制数和寄存器中的值进行位与&操作,实现特定位清零。
位与&运算符特点(二进制数)与1位与无变化;与0位与变为0;

把0xaaaa aaaa的低8-15位清零。
第一步:要把0xaaaa aaaa这个十六进制数的低8到15位清零,就得让8-15位和0位与,而其他位不能发生变化;
第二步:要得到一个十六进制数,让该数的8-15位是0,其他位是1,即二进制数的0-31位是:1111 1111 1111 1111 0000 0000 1111 1111;
第三步:把这个二进制数转换为十六进制数得到0xffff 00ff;
第四步:让寄存器中的目标数(0xaaaa aaaa)和清零指定位(0xffff 00ff)进行位与,即可完成8-15位清零;

//1010 1010 1010 1010 '1010 1010' 1010 1010 十六进制一位等于二进制四位
a = 0xaaaa aaaa;
//1111 1111 1111 1111 '0000 0000' 1111 1111
b = 0xffff 00ff;
c = a & b;
//1010 1010 1010 1010 '0000 0000' 1010 1010 这样8-15位就被清零了, 结果为0xaaaa 00aa
c == 0xaaaa 00aa;

2.2、对寄存器某几位赋值 |

寄存器位经过清零操作后,可以构造一个合适的二进制数和寄存器中的值进行位或|操作,实现对清零位的赋值;
位或|运算符特点(二进制数)与1位或变为1,与0位或无变化;

把0xaaaa 00aa清零的低8-15位置1,其他位不变。
第一步:要对0xaaaa 00aa这个十六进制数的第8-15位赋值,就得让8-15位和1位或,而其他位不能发生变化;
第二步:要得到一个十六进制数,让该数的8-15位是1,其他位是0,即二进制数的0-31位是:0000 0000 0000 0000 1111 1111 0000 0000;
第三步:把这个二进制数转换为十六进制数得到0xff00;
第四步:将寄存器中的数(0xaaaa 00aa)和赋值指定位(0xff00)进行位或,即可完成8-15位置1。

//1010 1010 1010 1010 '0000 0000' 1010 1010
a = 0xaaaa 00aa;
//0000 0000 0000 0000 '1111 1111' 10000 0000
b = 0xff00;
c = a | b;
//1010 1010 1010 1010 '1111 1111' 1010 1010 这样8-15位就被置1了。结果为0xaaaa ffaa
c = 0xaaaa ffaa;

2.3、对寄存器某位取反 ~或^

要对寄存器的某个位进行取反操作,即 1 变 0 ,0 变 1;
有以下两种方式:

2.3.1、按位取反 ~

位取反运算符特点:(二进制数)按位取反,1变为0,0变为1;

把0xf0取反。
第一步:将0xf0取反,首先要得到它的二进制。0xf0的二进制数是:1111 0000;
第二步:对二进制每一位进行取反,0变1, 1变0;
第三步:取反后得到0000 1111,转换成十六进制是:0xf

a = 0xf0;// 1111 0000
c = ~b;
c == 0xf;//0000 1111 注意:这里的变量都占32位,这里省略了8-31位,用不到的位,编译器自动补0

2.3.2、特定位取反用 ^

位异或运算符特点(二进制数)与1异或位取反,与0异或无变化;异或就是相异为1,相同则为0。

把0xa的0-1位取反,其他位不改变。
第一步:把0xa转换为二进制数:0xa->1010;
第二步:可以构造一个合适的二进制数和寄存器中的值进行位异或操作,实现对特定位的取反;为对二进制数1010的0-1位取反,则这里构建的对应二进制数位 :0011;
第三步:将构建的二进制数转换成十六进制的,0011->0x3;

a = 0xa;//10'10'   
b = 0x3; //00'11'   
c = a^b;   
c == 0x9; //10'01' 这样0xa的0-1位就取反了,而其他位没有发生变化

2.4、总结:

1、十六进制一位等于二进制四位,32位平台下int数据类型占32位,寄存器也是32位的,分配的变量占32位,我们用不到的位,编译器自动补0。
2、注意位取反~位异或^的区别。前者是给所有位取反的;后者可以完成给特定位取反。


3.位运算构建特定二进制数

对寄存器位操作,经常需要特定位给特定值或者取反;一般通过事先构建一个特别的值,将这个值和原来的值进行位与、位或、位异或、位取反等操作,来达到我们对寄存器操作的要求。构建特定位二进制数值,一般通过以下两种方式

3.1、构建特定位为1的二进制数:左位移、位或

构建目标特定位为1的二进制数:(0xT_V << T_Low_Bit_Index)

解释:

0x:16进制的前缀;
T_V:Target_Value 根据一个低位到高位连续T_L个1构建出来的二进制数,进而转换出来的十六进制数;
T_L: Target_Length 目标特定位长度, 目标特定位的((最高位inedx - 最低位index) + 1) = T_L;
T_Low_Bit_Index:目标特定位的最低位的下标

实现步骤:

1、计算出目标特定位的个数T_L;
2、根据T_L数量,先构建最低位为T_L个连续1的二进制数;
3、将上步骤中构建的二进制数,转换成十六进制数0xT_V;
4、然后将十六进制数0xT_V,左位移T_Low_Bit_Index个位;
5、得出构建目标特定位为1的二进制数:(0xT_L << T_Low_Bit_Index)
⚠️注意:目标特定位必须是连续性的,若不连续就将目标特定位的个数分成多个部分计算并列出来,构建出多个二进制数进行位或运算;

举例:
  • 构建一个bit3~bit7为1(其他位全部为0)的二进制数。

1、计算目标特定位个数:T_L = ((7 - 3) + 1) = 5;// bit3、bit4、bit5、bit6、bit7等5位
2、构建最低位为T_L个连续1的二进制数:0000 0000 0000 0000 0000 0000 0001 1111;// T_L = 5;构建低位往高位连续5个1的二进制数
3、将上步骤中构建的二进制数,转换成十六进制数:T_V = 0x1f; // 0x1f代表11111,在16进制数来看,低4个位为一个f,加上第5位1,就是0x1f
4、代入目标特定位的最低位的下标:T_Low_Bit_Index = 3;// bit3~bit7的最低位bit3
5、得出构建bit3~bit7位为1的二进制数:
(0xT_V << T_Low_Bit_Index) = (0x1f << 3) = 0000 0000 0000 0000 0000 0000 1111 1000 = 0xf8;

  • 构建bit3~bit7,bit23~bit25两段目标特定位为1的二进制数。

// 第一段目标特定位为1的二进制数
1、var_num_1 = (0x1f << 3) = 0xf8 = 0000 0000 0000 0000 0000 0000 '1111 1'000;
// 第二段目标特定位为1的二进制数
2、var_num_2 = (0x7 << 23) = 0x3800000 = 0000 00'11 1'000 0000 0000 0000 0000 0000;
// 两段目标特定位为1的二进制数结合起来的二进制; 位或运算符特点:与1位或变成1,与0位或无变化;
3、result = (0x1f << 3) | (0x7 << 23) = 0x38000f8 = 0000 00'11 1'000 0000 0000 0000 '1111 1'000;


第一段目标特定位为1的二进制数
第二段目标特定位为1的二进制数
两段目标特定位为1二进制位或结果

3.2、构建特定位为0的二进制数:左位移、位或、位取反

有以下两种实现方法

1、可以根据构造多个特定位为1的二进制数,进行位或操作:(0xT_V << T_Low_Bit_Index) | (0xT_V << T_Low_Bit_Index)
2、先将目标特定位为0的二进制数,取反变成构造目标特定位为1的二进制数;然后取反得到目标特定位为0的二进制数:~(0xT_V << T_Low_Bit_Index)

举例:
  • 构建一个bit3~bit7为0(其他位全部为1)的二进制数。

方法一:
目标特定位为0的二进制数:(0xT_V << T_Low_Bit_Index) | (0xT_V << T_Low_Bit_Index) = (0x7<<0) | (0xffffff<<8);// bit0-bit2,bit8-bit31两部分二进制数进行位或,得出目标特定位为0,其他位全位1
方法二:// 推荐
目标特定位为0的二进制数:~(0xT_V << T_Low_Bit_Index) = ~(0x1f << 3) // 直接将特定位为1的二进制数,取反

3.3、总结

1、寄存器中二进制数位:1少0多,可通过连续多个1左移n位,构造特定位为1二进制数;
2、寄存器中二进制数位:0少1多,先构建其位反二进制再按位取反
3、寄存器中二进制数位:连续1(0)不止一个,则通过分段分别构建,再彼此位或即可;


写在最后

C语言操作寄存器的常见手法
进制转换图表与讲解

相关文章

  • 巧妙运用C语言位运算

    巧妙运用C语言位运算,C语言是面向过程的,而C++是面向对象的 位运算 位运算的运算分量只能是整型或字符型数据,位...

  • C语言位运算

    C语言位运算_C语言中文网 C语言位域(位段)_C语言中文网

  • 2018-06-11c语言位运算

    位运算 Ps:位运算符是指进行二进制的运算。C语言中提供的位运算包括,与(&)、或(|)、异或(^)、取反(~)、...

  • 2018-06-06位运算

    位运算 Ps:位运算符是指进行二进制的运算。C语言中提供的位运算包括,与(&)、或(|)、异或(^)、取反(~)、...

  • 零基础到大神学习C语言必须要掌握的三点,一定要了解

    一.学好C语言的运算符和运算顺序 这是学好《C程序设计》的基础,C语言的运算非常灵活,功能十分丰富,运算种类远多于...

  • 16_位运算符分析

    关键词: C语言中的位运算符、 左移和右移注意点、位运算防错准则、 位运算符和逻辑运算符的区别 1. C语言中的位...

  • C语言 位运算

    ###位运算的逻辑: 1:(位与)运算符(&):双目操作符,当两个位进行相与时,只有两者都为“1”时结果才为“1”...

  • C语言位运算

    C语言里位运算就是对一个比特(Bit)进行操作,比特(Bit)是计算机的一个电子元件,只有通电和断电两种状态(这也...

  • c语言位运算

  • 位运算

    Ps:位运算符是指进行二进制的运算。C语言中提供的位运算包括,与(&)、或(|)、异或(^)、取反(~)、移动(“...

网友评论

      本文标题:C语言基础之位运算(二)

      本文链接:https://www.haomeiwen.com/subject/dcakddtx.html