所谓位运算,就是对一个比特(Bit)位进行操作。在《数据在内存中的存储》一节中讲到,比特(Bit)是一个电子元器件,8个比特构成一个字节(Byte),它已经是粒度最小的可操作单元了。

C语言提供了六种位运算符:

运算符 & | ^ ~ << >>
说明 按位与 按位或 按位异或 取反 左移 右移

按位与运算(&)

一个比特(Bit)位只有 0 和 1 两个取值,只有参与&运算的两个位都为 1 时,结果才为 1,否则为 0。例如1&1为 1,0&0为 0,1&0也为 0,这和逻辑运算符&&非常类似。

C语言中不能直接使用二进制,&两边的操作数可以是十进制、八进制、十六进制,它们在内存中最终都是以二进制形式存储,&就是对这些内存中的二进制位进行运算。其他的位运算符也是相同的道理。

例如,9 & 5可以转换成如下的运算:

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
    0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0001  (1 在内存中的存储)

也就是说,按位与运算会对参与运算的两个数的所有二进制位进行&运算,9 & 5的结果为 1。

又如,-9 & 5可以转换成如下的运算:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
    0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)

-9 & 5的结果是 5。

关于正数和负数在内存中的存储形式,我们已在VIP教程《整数在内存中是如何存储的,为什么它堪称天才般的设计》中进行了讲解。

再强调一遍,&是根据内存中的二进制位进行运算的,而不是数据的二进制形式;其他位运算符也一样。以-9&5为例,-9 的在内存中的存储和 -9 的二进制形式截然不同:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (-9 的二进制形式,前面多余的 0 可以抹掉)

按位与运算通常用来对某些位清 0,或者保留某些位。例如要把 n 的高 16 位清 0 ,保留低 16 位,可以进行n & 0XFFFF运算(0XFFFF 在内存中的存储形式为 0000 0000 -- 0000 0000 -- 1111 1111 -- 1111 1111)。

【实例】对上面的分析进行检验。

#include <stdio.h>

int main(){
int n = 0X8FA6002D;
printf("%d, %d, %X\n", 9 & 5, -9 & 5, n & 0XFFFF);
return 0;
}

运行结果:
1, 5, 2D

按位或运算(|)

参与|运算的两个二进制位有一个为 1 时,结果就为 1,两个都为 0 时结果才为 0。例如1|1为1,0|0为0,1|0为1,这和逻辑运算中的||非常类似。

例如,9 | 5可以转换成如下的运算:

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
|   0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
    0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1101  (13 在内存中的存储)

9 | 5的结果为 13。

又如,-9 | 5可以转换成如下的运算:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
|   0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
    1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)

-9 | 5的结果是 -9。

按位或运算可以用来将某些位置 1,或者保留某些位。例如要把 n 的高 16 位置 1,保留低 16 位,可以进行n | 0XFFFF0000运算(0XFFFF0000 在内存中的存储形式为 1111 1111 -- 1111 1111 -- 0000 0000 -- 0000 0000)。

【实例】对上面的分析进行校验。

#include <stdio.h>

int main(){
int n = 0X2D;
printf("%d, %d, %X\n", 9 | 5, -9 | 5, n | 0XFFFF0000);
return 0;
}

运行结果:
13, -9, FFFF002D

按位异或运算(^)

参与^运算两个二进制位不同时,结果为 1,相同时结果为 0。例如0^1为1,0^0为0,1^1为0。

例如,9 ^ 5可以转换成如下的运算:

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
^  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
    0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1100  (12 在内存中的存储)

9 ^ 5的结果为 12。

又如,-9 ^ 5可以转换成如下的运算:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
^  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
    1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0010  (-14 在内存中的存储)

-9 ^ 5的结果是 -14。

按位异或运算可以用来将某些二进制位反转。例如要把 n 的高 16 位反转,保留低 16 位,可以进行n ^ 0XFFFF0000运算(0XFFFF0000 在内存中的存储形式为 1111 1111 -- 1111 1111 -- 0000 0000 -- 0000 0000)。

【实例】对上面的分析进行校验。

#include <stdio.h>

int main(){
unsigned n = 0X0A07002D;
printf("%d, %d, %X\n", 9 ^ 5, -9 ^ 5, n ^ 0XFFFF0000);
return 0;
}

运行结果:
12, -14, F5F8002D

取反运算(~)

取反运算符~为单目运算符,右结合性,作用是对参与运算的二进制位取反。例如~1为0,~0为1,这和逻辑运算中的!非常类似。。

例如,~9可以转换为如下的运算:

~ 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
-----------------------------------------------------------------------------------
   1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0110  (-10 在内存中的存储)

所以~9的结果为 -10。

例如,~-9可以转换为如下的运算:

~ 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-----------------------------------------------------------------------------------
   0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1000  (8 在内存中的存储)

所以~-9的结果为 8。

【实例】对上面的分析进行校验。

#include <stdio.h>

int main(){
printf("%d, %d\n", ~9, ~-9 );
return 0;
}

运行结果:
-10, 8

左移运算(<<)

左移运算符<<用来把操作数的各个二进制位全部左移若干位,高位丢弃,低位补0。

例如,9<<3可以转换为如下的运算:

<< 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
-----------------------------------------------------------------------------------
     0000 0000 -- 0000 0000 -- 0000 0000 -- 0100 1000  (72 在内存中的存储)

所以9<<3的结果为 72。

又如,(-9)<<3可以转换为如下的运算:

<< 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-----------------------------------------------------------------------------------
      1111 1111 -- 1111 1111 -- 1111 1111 -- 1011 1000  (-72 在内存中的存储)

所以(-9)<<3的结果为 -72

如果数据较小,被丢弃的高位不包含 1,那么左移 n 位相当于乘以 2 的 n 次方。

【实例】对上面的结果进行校验。

#include <stdio.h>

int main(){
printf("%d, %d\n", 9<<3, (-9)<<3 );
return 0;
}

运行结果:
72, -72

右移运算(>>)

右移运算符>>用来把操作数的各个二进制位全部右移若干位,低位丢弃,高位补 0 或 1。如果数据的最高位是 0,那么就补 0;如果最高位是 1,那么就补 1。

例如,9>>3可以转换为如下的运算:

>> 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
-----------------------------------------------------------------------------------
     0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0001  (1 在内存中的存储)

所以9>>3的结果为 1。

又如,(-9)>>3可以转换为如下的运算:

>> 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-----------------------------------------------------------------------------------
      1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 1110  (-2 在内存中的存储)

所以(-9)>>3的结果为 -2

如果被丢弃的低位不包含 1,那么右移 n 位相当于除以 2 的 n 次方(但被移除的位中经常会包含 1)。

【实例】对上面的结果进行校验。

#include <stdio.h>

int main(){
printf("%d, %d\n", 9>>3, (-9)>>3 );
return 0;
}

运行结果:
1, -2

C语言:位运算的更多相关文章

  1. C语言位运算

    C语言位运算详解    位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C语言提供了6个位操作运算符.这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,shor ...

  2. C语言位运算+实例讲解(转)

    按位或 按位与 按位异或 按位取反 左移右移 C语言位运算 有6种: &, | , ^(亦或), >(右移). 注意:参与位运算的元素必须是int型或者char型,以补码形式出现. 按位 ...

  3. C语言位运算详解[转]

    作者:911 说明:本文参考了http://www2.tsu.edu.cn/www/cjc/online/cyuyan/,算是对其的修正,在此将本文列为原创,实有抄袭之嫌疑.甚是惭愧! 位运算是指按二 ...

  4. C语言位运算详解

    位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C语言提供了6个位操作运算符.这些运算符只能用于整形操作数,即只能用于带符号或无符号的char.short.int与long类型 ...

  5. C语言 位运算

    1G=1024M; 1M=102KB; 1KB=1024B(字节); 1B=8bits(位); #include<stdio.h> #include<stdlib.h> //C ...

  6. C语言位运算详解(转载)

    转载自:http://www.cnblogs.com/911/archive/2008/05/20/1203477.html 位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C ...

  7. C 语言 ----位运算

    位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C语言提供了6个位操作 运算符.这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类 ...

  8. C语言位运算、移位运算 经典示例

    概述: C语言的位级运算可以运用到任何“整数”的数据类型上,如char.short.int.long.long long.或者unsigned这样的限定词.基本的位运算有与.或.非.异或等等. C语言 ...

  9. C语言位运算题解

    #include <stdio.h> #include <stdlib.h> #include <string.h> //#define NONBLANK 1 ma ...

  10. 嵌入式C语言位运算之清位置位

    如题,在嵌入式开发中,掌握位运算是节省开发时间和提高开发效率的一种高效方式. 我们不得不去熟悉如何快速掌握位运算这种高效的技巧,接下来看看程序.. #include <stdio.h> # ...

随机推荐

  1. 人工智能AI Boosting HMC Memory Chip

    人工智能AI Boosting HMC Memory Chip Innosilicon的AI Boosting HMC存储芯片适用于高速,高带宽和高性能存储领域,例如AI边缘,数据中心,自动化等. H ...

  2. MinkowskiPooling池化(上)

    MinkowskiPooling池化(上) 如果内核大小等于跨步大小(例如kernel_size = [2,1],跨步= [2,1]),则引擎将更快地生成与池化函数相对应的输入输出映射. 如果使用U网 ...

  3. 实时双频Wi-Fi如何实现下一代车内连接

    实时双频Wi-Fi如何实现下一代车内连接 How real simultaneous dual band Wi-Fi enables next-generation in-vehicle connec ...

  4. MySQL面试题汇总

    事务是什么? 一系列操作,要么全部完成,要么一个都不做 事务的ACID特性 原子性:一系列操作要么都执行,要么都不执行 一致性:事务执行前后数据完整性不变,如转账前后总金额不变 隔离性:多个事务并发访 ...

  5. 从实力的角度出发来思考这道AOP题目

    文/楠木大叔 技术更迭,一往无前.技术人总是要不断学习以适应社会的发展和行业对我们的要求.每隔一段时间,就会有纷至沓来的新技术,新知识,新概念,我们应该如何应对,是被逼到墙角,还是主动出击? 导读 从 ...

  6. Golang学习(用代码来学习) - 第三篇

    type Books struct { title string author string subject string id int } /** 结构体的学习 */ func struct_tes ...

  7. 使用远程Docker进行集成测试

    目录 需求背景 使用docker进行环境搭建 以中心化的docker server改进集成测试 Docker Server远程链接配置 Testcontainers 框架 Testcontainers ...

  8. Unity3D学习笔记2——绘制一个带纹理的面

    目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...

  9. 自定义组件开发:使用v-model封装el-pagination组件

    1.前言 通过封装el-pagination组件开发自定义分页组件的类似文章网上已经有很多了,但看了一圈,总是不如意,于是决定还是自己动手搞一个. 2.背景 2.1.常规分页处理方法 利用el-pag ...

  10. intelliJ idea 自动修复eslint语法问题

    在要修复代码的文件上或全选需要修复的代码,快捷键:ctrl+shift+a,调出Find Action面板.搜索fix eslint problems,点击此操作,自动修复完成.