位操作在寄存器中的作用

寄存器是用来管理硬件的,所以读写寄存器就是操纵硬件。
怎么操纵寄存器? 三部曲读改写,读改写的意思,就是先把寄存器的值读出来,修
改寄存器中部分位的内容后再写回到寄存器中去。 由于我们操作寄存器时往往只需
要修改寄存器的特定几位就可以了(其它位不能改变),但是寄存器只能按照比如32
位来整个进行读写, 并不能只读写寄存器中特定的一些位,这里就产生了一个矛
盾, 那怎么解决这个问题呢? 常用的方法有以下3种:

1、位与&可以用来清零某些位而不改变其它位 位与:任何数(0或1)与0相与为
0, 与1相与为它自己,所以只要寄存器中的数的某些位与0相与,其它位与1相与
即可

//位与&清零寄存器中的BIT4~BIT7位而不改变其它位
unsigned int a = 0x1234ABCD, b = 0xFFFFFF0F;
unsigned int c;     
c = a & b; //0x1234AB0D 
printf("c = 0x%x\n", c);

2.位或|可以用来置1某些位而不改变其它位 位或|:任何数(0或1)与1相或为
1,与0相或则为它自己。

//位或|置1寄存器中的BIT8~BIT15位而不改变其它位
unsigned int a = 0x1234ABCD, b = 0x0000FF00;
unsigned int c;     
c = a | b; //0x1234FFCD
printf("c = 0x%x\n", c);

3.位异或^可以用来取反某些位而不改变其它位 位异或^: 任何数(0或1)与1异
或则取反,与0异或则为它自己。

//位异或^取反寄存器中的BIT8~BIT11位而不改变其它位
unsigned int a = 0x1234ABCD, b = 0x00000F00;
unsigned int c;     
c = a ^ b; //0x1234A4CD
printf("c = 0x%x\n", c);

用位与&、位或|、位异或^可以分别用来对寄存器的某些位进行清理、置1、取反操
作,但是需要构建一个32位的由0和1构成的数来满足我们的要求 ,比较麻烦,需
要依赖软件工具、计算器或者大脑来计算得到,不是很直观,因为不好理解,代码
的可读性会变差, 所以可以通过以下方法构造特定二进制数来实现。

4.通过移位(<<或>>)和位或来实现。

//构造一个bit7~bit12是1,其余位全是0的数
    (0x3F<<7)

//构造一个bit0~bit2、bit7~bit12、bit18~bit21为1,其余位全是0的数
    ((7<<0)|(0x3F<<7)|(0xF<<18))

代码实现:

//构造一个bit7~bit12是1,其余位全是0的数

unsigned int a;     
a = (0x3F<<7); //0x1F80     
printf("a = %x.\n", a); 

//构造一个bit0~bit2、bit7~bit12、bit18~bit21为1,其余位全是0的数

unsigned int a;     
a = ((7<<0)|(0x3F<<7)|(0xF<<18)); //0x3C1F87    
printf("a = %x.\n", a);

5.通过取反和移位来构造特定的二进制数

//构造一个bit5~bit9是0,其余位全是1的二进制数
//方法一:(0x1F<<0)|(0x7FFFFF<<10) 用移位<<和或|操作实现,比较笨的方法  
//方法二:~(0x1F<<5) 先构建一个位反数,然后取反得到,比较聪明的方法  

代码实现:

//构造一个bit5~bit9是0,其余位全是1的二进制数       
//方法一:比较笨的方法

unsigned int a;     
a = (0x1F<<0)|(0x7FFFFF<<10); //0xFFFFFC1F      
printf("a = %x.\n", a);

//方法二:比较聪明的方法

unsigned int b;     
b = ~(0x1F<<5); //0xFFFFFC1F    
printf("b = %x.\n", b);

一般来说,如果需要构建的二进制数中大多数是0,少数是1,可以通过移位的
方法来构造; 如果需要构建的二进制数中大多数是1,少数是0,可以通过移
位构建位反数然后取反的方法来构造; 如果有多段连续1的数出现,则可以分
段移位然后或起来叠加得到。

6.位操作的相关练习:
回顾:要置1用|,用清零用&,要取反用^,~和<<、>>用来构建特定二进制数。

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

a |= (1<<3);

②给定一个整型数a,设置a的bit3~bit7,保持其他位不变。

a |= (0x1F<<3); 或者 a |= (0b11111<<3);

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

a &= (~(1<<15));

④给定一个整形数a,清除a的bit15~bit23,保持其他位不变。

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

⑤给定一个整形数a,取出a的bit3~bit8。

//保持bit3~bit8的数不变,其它位全部清零。然后再右移3位。
a &= (0x3F<<3);
a >>= 3;

⑥用C语言给一个寄存器的bit7~bit17赋值937(其余位不受影响)。

//把bit7~bit17清零或者置1,其余位不变,然后位或或者位与0x3A9
a &= (~(0x7FF<<7));
a |= (0x3A9<<7);

⑦用C语言将一个寄存器的bit7~bit17中的值加17(其余位不受影响)。

b= a &(0x7FF<<7);
b >>= 7;
b += 17;

a &= (~(0x7FF<<7));
a |= (b<<7);

⑧用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17.

a &= (~((0x7FF<<7) | (0x1F<<21)));
a |= ((0x3A9<<7) | (0x11<<21));

代码验证:

//给定一个整型数a,设置a的bit3,保证其他位不变。
unsigned int a = 0;
a |= (1<<3); //0x8
printf("a = 0x%x.\n", a);

//给定一个整型数a,设置a的bit3~bit7,保持其他位不变。
/*unsigned int a = 0;
//a |= (0x1F<<3);  //0xf8
a |= (0b11111<<3); //0xf8
printf("a = 0x%x.\n", a); */

//给定一个整型数a,清除a的bit15,保证其他位不变。
/*unsigned int a = 0xFFFFFFFF;
a &= (~(1<<15)); //0xFFFF7FFF
printf("a = 0x%x.\n", a); */

//给定一个整形数a,清除a的bit15~bit23,保持其他位不变。
/*unsigned int a = 0xFFFFFFFF;
a &= (~(0x1FF<<15)); //0xFF007FFF
printf("a = 0x%x.\n", a);*/ 

//给定一个整形数a,取出a的bit3~bit8。
/*unsigned int a = 0xFFFF1234;
a &= (0x3F<<3); //0x30
a >>= 3; //0x6
printf("a = 0x%x.\n", a); */

//用C语言给一个寄存器的bit7~bit17赋值937(其余位不受影响)。
/*unsigned int a = 0xFFFF1234;
a &= (~(0x7FF<<7)); 
a |= (0x3A9<<7);    //0xfffdd4b4
printf("a = 0x%x.\n", a); */

//用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17.
/*unsigned int a = 0xFFFF1234, b;
b= a &(0x7FF<<7);
b >>= 7;
b += 17;

a &= (~(0x7FF<<7));
a |= (b<<7); //0xffff1ab4
printf("a = 0x%x.\n", a); */

//用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17.
unsigned int a = 0xFFFF1234;
a &= (~((0x7FF<<7) | (0x1F<<21)));
a |= ((0x3A9<<7) | (0x11<<21)); //0xfe3dd4b4                                                                                                                     
printf("a = 0x%x.\n", a);