C语言-位运算-小结

一.位运算的概念

各种运算都是以字节作为最基本位进行的很多系统程序中常要求在位(bit)一级进行运算或处理。常见的位运算运算符:

& 按位与
| 按位或
^ 按位异或
~ 取反
<< 左移
>> 右移

二.位运算的运算方式

1.按位与运算

按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现。

例如:9&5可写算式如下:
00001001 (9的二进制补码)
&00000101 (5的二进制补码) = 00000001

按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 ,保留低八位,可作a&255运算( 255 的二进制数为0000000011111111)。

按位与的两种经典应用:

  • 让某一位或某些位为0 : X & 0XFE
  • 取一个数中的一段 : X & 0XFF

2.按位或运算

按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。

例如:9|5可写算式如下:
00001001
| 00000101 = 00001101 (十进制为13) 可见9|5=13

按位或的两种经典应用:

  • 使得一位或几个位为1 : X | 0X01(使最低位为1)
  • 把两个数拼起来 : 0X00FF | 0XFF00 = 0XFFFF

3.按位异或运算

按位异或运算符“”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1,否则为0。参与运算数仍以补码出现,例如95可写成算式如下:

  00001001 

^ 00000101 = 00001100 (十进制为12)

按位或

4.求反运算

求反运算符~为单目运算符,具有右结合性。其功能是对参与运算的数的各二进位按位求反。

例如~9的运算为:
~(0000000000001001)结果为:1111111111110110

5.左移运算

左移运算符“<<”是双目运算符。其功能把“<< ”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0。

例如:
a<<4

指把a的各二进位向左移动4位。如a=00000011(十进制3),左移4位后为00110000(十进制48)。

特性:将一个数左移n位,则得到该数与2的n次方的乘积,即 X <<= 2 <=> x *= 2^n

6.右移运算

右移运算符“>>”是双目运算符。其功能是把“>> ”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。

例如:
设 a=15, a>>2 表示把000001111右移为00000011(十进制3)。

应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补 0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。

特性:将一个数左移n位,则得到该数与2的n次方的商,即 X <<= 2 <=> x /= 2^n

注意!移位的位数不可为复数!no zuo no die!

一个实例:输出一个十进制数的二进制形式

#include

int main(){
	int number;
	scanf("%d", &number);
	unsigned in flag = 1u << 31;  
    //1为最低为为1的数,1u表示这是一个unsigned类型的(二进制)数值,左移31位后是最高位为1的二进制数
	for( ; flag; flag >>= 1){
		printf("%d", number & flag ? 1:0);//flag的作用是逐比特与number按位与输出0/1并后移
	}
	printf("\n");
	return 0;
} 

原理图:

C语言-位运算-小结_第1张图片

另一个实例: 单片机参数操作
C语言-位运算-小结_第2张图片

欲要对该SFR寄存器进行操作,例如对位于第2Bit的Stop Bit Select和第3Bit的Parity Enable的状态置1或置0,操作代码如下:

const unsigned int SBS = 1u << 2;	//SBS左移到第2Bit
const unsigned int PE = 1u << 3;	//PE左移到第3Bit

U0LCR |= SBS | PE;		//SBS|PE 使第2、3Bit保持为1,再按位与,无论原位为和值均可得到1
U0CLR &= ~(SBS|PE);		//原理类似上面,取反后按位或可以清除这两个Bit位得到0

三.位域 (位段)

1.解释

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C++语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

2.定义和说明

位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

struct 位域结构名{
    类型说明符 位域名:位域长度;
}
//例如:
struct bs{
    int a : 8;
    int b : 2;
    int c : 6;
}
//与结构体相似,可以同时定义变量
struct bs{
    int a : 8;
    int b : 2;
    int c : 6;
}data;
//说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。

说明

  1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
struct bs{        
	unsigned a:4        
	unsigned  :0       //空域*      
	unsigned b:4       //从下一单元开始存放      
	unsigned c:4 
}
//在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。 
  1. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。

  2. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。

  3. 当所需要的位超过一个int时会使用多个int

struct k{       
    int a:1       
    int  :2          //该2位不能使用       
    int b:3      
    int c:2 
}; 

3.位域的使用位域的使用和结构成员的使用相同,

其一般形式为: 位域变量名·位域名

​ 位域在本质上也是结构类型,不过它的成员按二进制位分配内存。其定义、说明及使用的方式都与结构相同。

​ 位域提供了一种手段,使得可在高级语言中实现数据的压缩,节省了存储空间,同时也提高了程序的效率。

本文章部分内容涉及出版物、课程教授知识,如有侵权,请联系我删除!
同时,本文为课堂随笔记录,存在不足之处望大神指正~ PS:新人求赞~

你可能感兴趣的:(C语言学习记录)