惧留孙网

juliusun.com

在线教程 > C语言教程 > 位运算

位运算

第 49/50 节 冥河C语言教程


内存中的数据都是以二进制的形式存放的,二进制只有0和1。一个0或1表示一位,英文名为bit。8位组成1个字节,英文名byte。位运算就是对每一位的二进制0或1进行运算。

本节我们需要介绍的运算符如下:

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

注意区分一下,两个取地址符&&是逻辑运算符并,一个取地址运算符&是位运算按位与。两个竖线是逻辑运算符或,一个竖线是位运算按位或。

位运算两个数组数大小不一致时,对于无符号类型,将占用内存小的数字高位补0,达到相同位数再运算。对于有符号类型,将占用内存小的数字高位补符号位(即正数补0负数补1)再运算。

按位与& 作用是将两个数字相对应的位进行与运算,与运算的结果是,两个二进制位,均为1,结果才为1,否则为0。按位与运算规则如下:

表达式结果
0 & 0 0
0 & 1 0
1 & 0 0
1 & 1 1

本段无特殊说明,进制均是二进制,如 1010 & 0011 = 0010。最高位为第1位,最低位为第4位。则第一位为1&0=0,第二位0&0=0,第三位1&1=1,第四位0&1=0。组合一下第1到第4位结果为0010。1010、0011、0010换算成10进制分别为10、3、2,换算成16进制分别为a、3、2。

代码用unsigned char类型说明,char占8位,方便起见,高4位为0不考虑:


  1. unsigned char a = 0xa,b=3,c = a & b; //char占用1个字节即8位,使用无符号排序符号干扰。对应二进制1010,0011及0010
  2. printf("%d %d %d\n",a,b,c); //用10进制输出三个数字,输出结果为10 3 2
  3. printf("%x %x %x\n",a,b,c); //用16进制输出三个数字,输出结果为a 3 2

标准C语言没有以二进制输出数字的格式,有点不方便,不过节后面会给出一个将数字转换成二进制并输出的例子。

按位或| 作用是将两个数字对应的二进制位进行或运算,两边的二进制至少有一方为1结果即为1。换个说法就是两边的二进制均为0,结果才为0,否则为1。按位或规则如下:

表达式结果
0 | 0 0
0 | 1 1
1 | 0 1
1 | 1 1

本段无特殊说明,进制均是二进制,如 1010 | 0011 = 1011。最高位为第1位,最低位为第4位。则第一位为1 | 0= 1,第二位0 | 0=0,第三位1 | 1=1,第四位0 | 1=1。组合一下第1到第4位结果为1011。1010、0011、1011换算成10进制分别为10、3、11,换算成16进制分别为a、3、b。


  1. unsigned char a = 0xa,b=3,c = a | b; //char占用1个字节即8位,使用无符号排序符号干扰。对应二进制1010,0011及1011
  2. printf("%d %d %d\n",a,b,c); //用10进制输出三个数字,输出结果为10 3 11
  3. printf("%x %x %x\n",a,b,c); //用16进制输出三个数字,输出结果为a 3 b

按位异或^ 作用是将两个数字对应的二进制位进行比较,相同为0,不同为1。按位异或规则如下:

表达式结果
0 ^ 0 0
0 ^ 1 1
1 ^ 0 1
1 ^ 1 0

本段无特殊说明,进制均是二进制,如 1010 ^ 0011 = 1001。最高位为第1位,最低位为第4位。则第一位为1 ^ 0= 1,第二位0 ^ 0=0,第三位1 ^ 1=0,第四位0 ^ 1=1。组合一下第1到第4位结果为1011。1010、0011、1011换算成10进制分别为10、3、9,换算成16进制分别为a、3、9。


  1. unsigned char a = 0xa,b=3,c = a ^ b; //char占用1个字节即8位,使用无符号排序符号干扰。对应二进制1010,0011及1001
  2. printf("%d %d %d\n",a,b,c); //用10进制输出三个数字,输出结果为10 3 9
  3. printf("%x %x %x\n",a,b,c); //用16进制输出三个数字,输出结果为a 3 9

以上例子注意,unsigned char a=0xa,由于a占用8位,补全应该是二进制0000 1010。由于以上例子高4位均为0,且0和0做与、或、异或运算仍然是0,因为排序了高位干扰,注意下unsigned char是占用8个二进制位的。

取反~ 一元运算符,后面接表达式。作用是如果二进制位为0,则结果为1;如果二进制位为1,则结果为0。取反规则如下:

表达式结果
~0 1
~1 0

本段无特殊说明,进制均是二进制,如 ~11111 1001 = 0000 0110。方便查看,高4位与低四位之间加了空格。1111 1001、0000 0110换算成10进制分别为249、6,换算成16进制分别为f9、6。

  1. unsigned char a = 0xf9,c=~a; //char占用1个字节即8位,使用无符号排序符号干扰。对应二进制1010,0011及0110
  2. printf("%d %d\n",a,c); //用10进制输出三个数字,输出结果为249 6
  3. printf("%x %x\n",a,c); //用16进制输出三个数字,输出结果为f9 6

左移运算符<< 用法为"数字O<<数字N"。使用的是将"数字O"二进制每位向高位(即左边)移动"数字N"位,右边补0,左边移出的部分省略。方便说明,没有字母前缀的为10进制数字,带有大写字母B前缀的为二进制数字,则B 0000 1111<<2 = B 0011 1100,另外一例:B1011 1111<<1 = B0111 1110,未左移前的最高位1被移出,舍弃不用。移动后最右边的0为自动补充。

例二进制1111 1001左移两位:


  1. unsigned char a = 0xf9,c=a<<2; //二进制1111 1001即0xf9为十进制249,二进制1110 0100即0xe4为二进制228
  2. printf("%d %d\n",a,c); //用10进制输出三个数字,输出结果为249 228
  3. printf("%x %x\n",a,c); //用16进制输出三个数字,输出结果为f9 e4

当左移N位时,如果左边舍弃的位无1,且是无符号或左移后最高位仍为0,起到的作用的乘以2的N次方。

右移运算符>> 用法为"数字O>>数字N"。使用的是将"数字O"二进制每位向低位(即右边)移动"数字N"位,右边移出的部分舍弃不用。左边填充时稍显复杂,无符号类型左右直接补0;有符号时,正数(即最高位为0)时左边补0,负数(即最高位为1)时左边补1或0依赖运行时的计算机系统。

左边填充规则总结一下,右移时,"数字O"为无符号类型或正数的有符号类型,左边补0,"数字O"为有符号且为负数时,左边补1或0依赖运行时的计算机系统。

本节只讨论无符号的情况,以下例子均以无符号数字右移为例。方便说明,没有字母前缀的为10进制数字,带有大写字母B前缀的为二进制数字,则B 0000 1111>>2 = B 0000 0011,另外一例:B1011 1111>>1 = B0101 1111。


例二进制0011 1001右移两位:


  1. unsigned char a = 0x39,c=a>>2; //二进制0011 1001即0x39为十进制57,二进制0000 1110即0x0e为二进制14
  2. printf("%d %d\n",a,c); //用10进制输出三个数字,输出结果为57 14
  3. printf("%x %x\n",a,c); //用16进制输出三个数字,输出结果为39 e

下面用位运算实现输出一个unsigned char类型的二进制:


  1. #include<stdio.h>
  2. int main(int argc, char *argv[ ] )
  3. {
  4. void show_bin(unsigned char i); //函数声明
  5. show_bin(127); //输出127的二进制
  6. getchar( ) ; //使程序暂停一下
  7. return 0;
  8. }
  9. void show_bin(unsigned char i )
  10. {
  11. for (int x = 7; x >= 0; --x)
  12. {
  13. if (3 == x) //高4位与低4位之间输出个空格分隔一下
  14. {
  15. printf(" ");
  16. }
  17. printf("%d", (i >> x) & 1); //需要输出的位移动到最低,再通过与二进制的0000 0001进行位与运算排序高位非0干扰
  18. }
  19. }

效果类似如下图:

Pic

效果图供供参考,不同平台有所差异。

作者:冥河 QQ:3304576112
交流QQ群:554701039 C语言讲课群
本教程内容由本站保留版权,请勿复制传播
抖音
©2015-2024 惧留孙网 juliusun.com

京ICP备15039193号-1

首页 教程 下载 文章 聊天 我的