——位运算)
Posted 二木成林
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了——位运算)相关的知识,希望对你有一定的参考价值。
12.1 位运算符
C语言提供了六种位运算符:
&
:按位与|
:按位或^
:按位异或~
:取反<<
:左移>>
:右移
12.1.1 按位与运算
按位与运算符"&
"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进制位均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现。如9&5
:
0000 1001 (9的二进制补码)
&0000 0101 (5的二进制补码)
=0000 0001 (1的二进制补码)
按位与运算通常用来对某些位清0或保留某些位。
#include <stdio.h>
int main()
int a = 9, b = 5, c;
c = a & b;
printf("%d&%d=%d", a, b, c);
12.1.2 按位或运算
按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的两个二进制位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。如9|5
:
0000 1001 (9的二进制补码)
|0000 0101 (5的二进制补码)
=0000 1101 (13的二进制补码)
即:
#include <stdio.h>
int main()
int a = 9, b = 5, c;
c = a | b;
printf("%d|%d=%d", a, b, c);// 9|5=13
12.1.3 按位异或运算
按位异或运算符“^
”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异(即两位二进制中一位是0,另外一位是1的情况)时,结果为1。参与运算数仍以补码出现。如9^5
:
0000 1001 (9的二进制补码)
^0000 0101 (5的二进制补码)
=0000 1100 (12的二进制补码)
即:
#include <stdio.h>
int main()
int a = 9, b = 5, c;
c = a ^ b;
printf("%d^%d=%d", a, b, c);// 9^5=12
12.1.4 求反运算
求反运算符~
为单目运算符,具有右结合性。其功能是对参与运算的数的各二进制位按位求反。如~9
:
~0000 1001 (9的二进制补码)
=1111 0110
即:
#include <stdio.h>
int main()
int a = 9, b;
b = ~a;
printf("~%d=%d", a, b);// ~9=-10
12.1.5 左移运算
左移运算符“<<
”是双目运算符。其功能把“<<
”左边的运算数的各二进制位全部左移若干位,由“<<
”右边的数指定移动的位数,高位丢弃,低位补0。如:
a=3;(3的二进制位为0000 0011)
a<<4=0011 0000
即:
#include <stdio.h>
int main()
int a = 3, b;
b = a << 4;
printf("%d<<4=%d", a, b);// 3<<4=48
12.1.6 右移运算符
右移运算符“>>
”是双目运算符。其功能是把“>>
”左边的运算数的各二进制位全部右移若干位,“>>
”右边的数指定移动的位数。应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。如:
a=15;(15的二进制是0000 1111)
a>>2=0000 0011
即:
#include <stdio.h>
int main()
unsigned int a = 15, b;
b = a >> 2;
printf("%d>>2=%d", a, b);// 15>>2=3
12.2 位域(位段)
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。
所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
即可以在一个字节中的不同位中存储不同的信息,把空间充分利用起来。
12.2.1 位域的定义和位域变量的声明
位域的定义语法如下:
struct 位域结构名
类型说明符 位域名: 位域长度;
...
;
例如:
struct bs
int a:8;
int b:2;
int c:6;
;
位域变量的声明:与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。如:
// 说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位
struct bs
int a:8;
int b:2;
int c:6;
data;
关于位域的定义的注意事项:
- 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
// 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位
struct bs
unsigned a:4
unsigned :0 /*空域*/
unsigned b:4 /*从下一单元开始存放*/
unsigned c:4
;
- 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进制。
- 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
struct k
int a:1
int :2 /*该2位不能使用*/
int b:3
int c:2
;
12.2.2 位域的使用
位域的使用和结构成员的使用相同,其一般形式为:
位域变量名·位域名
位域允许用各种格式输出。
#include <stdio.h>
struct bs
unsigned a: 1;
unsigned b: 3;
unsigned c: 4;
bit, *pbit;
int main()
bit.a = 1;// 二进制位是0000 0001,只需要1位二进制就能保存
bit.b = 7;// 二进制位是0000 0111,只需要3位二进制就能保存
bit.c = 15;
printf("%d,%d,%d\\n", bit.a, bit.b, bit.c);// 1,7,15
pbit = &bit;
pbit->a = 0;
pbit->b &= 3;
pbit->c |= 1;
printf("%d,%d,%d\\n", pbit->a, pbit->b, pbit->c);// 0,3,15
以上是关于——位运算)的主要内容,如果未能解决你的问题,请参考以下文章