十四、位运算
14.1 位运算符
符号 | 作用 |
---|---|
& | 按位与 |
I | 按位或 |
^ | 按位异或 |
~ | 取反 |
<< | 左移 |
>> | 右移 |
14.1.1 按位与运算
按位与运算符 “&” 是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0。参与运算的数以 补码 方式出现。eg. 9&5=1
14.1.2 按位或运算
按位或运算符 “|” 是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。eg. 9|5=13
14.1.3 按位异或运算
按位异或运算符 “^” 是双目运算符。其功能是参与运算的两数各对应的二进位相异
或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现。eg.9^5=12
14.1.4 求反运算
求反运算符 “~” 为单目运算符,具有右结合性。其功能是对参与运算的数的各二进位按位求反。eg. ~9
14.1.5 左移运算
左移运算符 “<<” 是双目运算符。其功能把 “<<” 左边的运算数的各二进位全部左移若干位,由 “<<” 右边的数指定移动的位数,高位丢弃,低位补0。
a<<4 //若a=00000011(十进制3),左移 4 位后为 00110000(十进制48)
等价于 a*(2的4次方)
14.1.6 右移运算
右移运算符 “>>” 是双目运算符。其功能是把 “>>” 左边的运算数的各二进位全部右移若干位, “>>” 右边的数指定移动的位数。低位丢弃,高位补0。
a=15; //二进制 00001111
a>>2; //右移2位,00000011(十进制3)
应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,最高位是补 0 或是补 1 取决于编译系统的规定。TurboC和很多系统规定为补1。
14.2 位域(位段)
14.2.1 概述
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为 “位域” 或 "位段” 。
所谓 “位域” 是 把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
14.2.2 位域定义
位域定义的形式:
struct 位域结构名
{
位域列表;
};
其中,位域列表的形式为:
类型说明符 位域名:位域长度
14.2.3 位域的使用
位域的使用(位域的使用和结构成员的使用相同):位域变量名.位域名
struct bs
{
int a:8;
int b:2;
int c:6;
}data, *pb;
//说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。
data.a = 12;
data.b = 3;
data.c = 24;
pb = &data;
pb->a = 0;
位域变量的说明与结构变量说明的方式相同。可采用先定义后说明,同时定义说明或者直接说明这三种方式。
对于位域定义的说明:
(1)一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
struct bs
{
unsigned a:4; //取值范围为 0~15
unsigned :0; // 空域
unsigned b:2; //取值范围为 0~3
unsigned c:6; //取值范围为 0~63
};
//在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用2位,c占用6位。
(2)由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
(3)位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
struct k
{
int a:1;
int :2; //该 2 位不能使用
int b:3;
int c:2;
};