C语言_位运算1

关于位运算相关内容分为两个大博文,分别为位运算1,即该博文;主要介绍二进制、位、字节的基本概念、进制转换问题,以及C的~ & | ^ 按位运算符及应用方法

由于篇幅限制,位运算2主要讲述左移和右移运算及编程练习以及字段运算

文章目录

    • 0.引入
        • 0.1 位运算的应用方向
        • 0.2 二进制数、位和字节
          • 0.2.1 二进制整数
          • 0.2.2 有符号整数
          • 0.2.3 二进制浮点数
    • 1. 其它进制数
    • 2. C按位运算符
        • 2.1 按位逻辑运算符
          • 2.1.1 二进制反码或按位取反:`~`
          • 2.1.2 按位与:`&`
          • 2.1.3 按位或:`|`
          • 2.1.4 按位异或:`^`
        • 2.2 按位运算符常见用法
          • 2.2.1 用法一:掩码
          • 2.2.2 用法二:打开位
          • 2.2.3 用法三:关闭位
          • 2.2.5 用法五:切换位
          • 2.2.6 用法六:检查位的值

0.引入

0.1 位运算的应用方向

  1. 想硬件设备发送一两个字节来控制这些设备,其中每个位(bit)都有特定含义
  2. 与文件相关的操作系统信息经常被存储,通过使用特定位表明特定项
  3. 许多压缩和加密操作都是直接处理单独的位

通过应用可以看出,位运算主要应用在计算机软件与硬件交互的过程中使用,或者可以说是更底层的东西

C语言也是编写设备驱动程序和嵌入式开发的首选语言

0.2 二进制数、位和字节

二进制数(binary number):

以2为基底表示的数字被称为二进制数

例如二进制数1101可表示为:1x23+1x22+0x21+1x20

二进制系统可以把任意整数表示为0和1的组合,关于进制转换问题请参考博文进制转换相关内容

0.2.1 二进制整数

通常,1字节包含8位。C语言用字节(byte)表示存储系统字符集所需的大小

所以C字节可能是8位、9位、16位或其它值。但是,描述存储器芯片和数据传输率中所用的字节指的是8位字节。

本博文内容假设1字节=8位
通常用用术语 八位组(octet) 这个术语特指8位字节

计算机中从左往右给八位分别变好7~0。编号为7的成为高阶位(high-order bit) ,编号是0的位称为低阶位(low-oder bit) 每一位对应2的相应指数
C语言_位运算1_第1张图片
如上图,1字节能表示的最大数字为11111111 其对应的十进制值为255

11111111=1x27+1x26+1x25+1x24+1x23+1x22+1x21+1x20=255

因此1字节可以存储0~255范围内的数字,总共256个值

对于unsigned char 中1字节存储范围为0~255,
对于signed char 中1字节表示范围为-128~+127

0.2.2 有符号整数

如何表示有符号整数取决于硬件,而不是C语言。一般地,C中用高阶位状态1表示负数,高阶位0表示正数

针对具体数的表示问题上及硬件关系,提出数的源码、反码、补码表示方法,具体请参见博文源码、反码、补码部分

0.2.3 二进制浮点数

浮点数分为两部分存储:二进制小数和二进制指数

1. 二进制小数表示方法

.101 的二进制表示为:1/21+0/22+1/23
.101 的十进制表示为:1/2+0/4+1/8=0.5+0+0.125
即,.101对应的十进制值为0.625

可以看出,二进制的表示法以2的指数进行计算,即二进制表示法只能精确的表示多个1/2的幂的和。

3/4和7/8可以精确的表示为二进制小数,但1/3和2/5却不能

2. 浮点数表示方法:

(此处没有理解)
C语言_位运算1_第2张图片

1. 其它进制数

其它进制数包括八进制和十六进制数,相关内容参看博文:八进制、十六进制部分

2. C按位运算符

C中有两个操作位的工具。第一个工具为一套(6个)作用于位的按位运算符,第二个工具是字段(field) 数据形式,用于访问int中的位。该部分将介绍相关按位运算符。

按位运算符分为两类:一类是按位逻辑运算符,另一类是位移运算符

2.1 按位逻辑运算符

对于按位逻辑运算符请注意:

  1. 4个按位逻辑运算符用于整型数据,包括char
  2. 按位(bitwise)运算是因为这些操作都是只针对每一位进行操作,而不影响它的左右两边的位。
  3. 不要把按位运算符于常规的逻辑运算符混肴,常规的逻辑运算符操作的是整个值

即,1字节8位,按位运算符对8位中的某一位操作,而常规逻辑运算符对整个字节操作
由于浮点型数据的表示上的特殊性,所以按位运算只在整型数据上应用

2.1.1 二进制反码或按位取反:~

一元运算符~将1变成0,0变成1
例如:

原始值10011010
进行取反操作:~(10011010)
结果值为:01100101

值得注意的是:

~不会改变原始值,但是该运算符创造了一个可以使用或赋值的新的值。

如:

int val=154;// val=10011010
int newVal=0;
newVal=~val;// ~(10011010)
printf("val=%d\t,newVal=%d\n",val,newVal);

C语言_位运算1_第3张图片

2.1.2 按位与:&

二元运算符&通过逐位比较两个运算对象,生成一个新值。

对于每个位,只有两个运算对象中相应的值都为1时,结果才为1(从真假方面看,只有当两个位都为真时,结果才为真)。

如:

int valA=147;// valA=10010011
int valB=61;//valB=00111101
int newVal=0;
newVal=valA&valB;// newVal=00010001
printf("valA=%d\n,valB=%d\n,newVal=%d\n",valA,valB,newVal);

C语言_位运算1_第4张图片

&=按位与运算符和赋值结合运算符,针对上面代码,可以写成如下形式

 int valA = 147;// valA=10010011
 valA &= 61;// ValA=00010001
 printf("valA=%d\n",valA);

C语言_位运算1_第5张图片

2.1.3 按位或:|

二元运算符| 通过逐位比较两个运算对象,生成一个新值。

对于每个位,如果两个运算对象中相应的位为1,结果就为1(从真假方面看,如果两个运算对象中相应的一个位为真或者两个位都为真,那么结果为真)

如:

int valA=163;//valA=10010011
int valB=61;//valB=00111101
int newVal=0;
newVal=valA|valB;//newVal=191
printf("valA=%d\nvalB=%d\nnewVal=%d\n",valA,valB,newVal);

C语言_位运算1_第6张图片

针对|=有如下书写
int val=163;
val |= 61; ====等价于 val= val|61;
此时val的值为191

2.1.4 按位异或:^

二元运算符^逐位比较两个运算对象。

对于每个位,如果两个运算对象中相应的位一个为1(但不是两个为1),结果为1(从真假方面看,如果两个运算对象中相应的一个位为真且不是两个位同为1,那么结果为真)

如:

int valA=147;//valA=10010011
int valB=61;//valB=00111101
int newVal=valA^valB;
printf("valA=%d\nvalB=%d\nnewVal=%d",valA,valB,newVal);

C语言_位运算1_第7张图片

同样有^=运算符
int val=147;
val ^= 61; ======等价于 val= val^61
val=174

2.2 按位运算符常见用法

2.2.1 用法一:掩码

按位与&运算符常用于掩码(mask)。

掩码指的是一些设置为开(1)或关(0)的位组合。

掩码的使用过程

设定义符号常量MASK=2(二进制形式为00000010)
则语句:

int flages=150;//flages=10010110
int MASK=2;//MASK=00000010
flages &= MASK;
printf("flages=%d\n",flages);

C语言_位运算1_第8张图片

表示掩码的使用,其作用过程如下

C语言_位运算1_第9张图片

2.2.2 用法二:打开位

有时,需要打开一个值中的特定位,同时保持其它位不变

例如,向一台IBM PC 通过向端口发送值来控制硬件;
例如,为了打开内置扬声器,必须打开1号位,同时保持其他位不变。这种情况可以使用按位或运算符

按位或|运算符常用于位的打开

例如:

int flages=31;//flages=00001111
int MASK=182;//MASK=10110110
flages |= MASK;
printf("flages=%d\n",flages);

C语言_位运算1_第10张图片

2.2.3 用法三:关闭位

将某个位值设为0,通常需要&运算符

如:

int MASK=182;//MASK=10110110
int flags=15;//falgs=00001111
flags &= ~MASK;
printf("flags=%d",flags);

C语言_位运算1_第11张图片

此操作关闭flags的第1 2 号位

2.2.5 用法五:切换位

切换位值得是打开已关闭的位或者关闭已打开的位

通常使用按位异或^运算符

如:

int flags=15;//flags=00001111
int MASK=182;//MASK=10110110
flags ^= MASK;
printf("flags=%d\n",flags);

C语言_位运算1_第12张图片

2.2.6 用法六:检查位的值

有时需要检查某位的值是否被设定为期望值

比如为比较flags中1号位的值是否为1
通常的做法为:

int MASK=2;//MASK=00000010
int flags=54;//flags=00110110
if((flags&MASK) == MASK)
{
     
	puts("number 2 has been set as 1");
}
else
{
     
	puts("number 2 set error");
}

C语言_位运算1_第13张图片

你可能感兴趣的:(C/C++)