本文采用了《C Primer Plus》、《C陷阱与缺陷》以及比特科技的教学视频。

对C语言位操作符与位移操作符进行了详细讲解,为了加深印象,每一个知识点均有例题和实用讲解

目录

位操作符

1.按(二进制)位与 &

2.按(二进制)位或  |

3.按(二进制)位异或  ^

4.按(二进制)位取反:~

位操作符用法

1.掩码

2.打开位(设置位)

3.关闭位(清空位)

位移操作符

1.左移操作符

2.右移操作符

位移操作符用法

1.用位移运算符把整数转换成二进制形式

2.转换某一个值的后n位


位操作符

1.按(二进制)位与 &

规则:对应位都为1时,结果为1,否则为0。

例如:

int a = 1,b = 3;

00000000 00000000 00000000 00000001  //a

00000000 00000000 00000000 00000011  //b

00000000 00000000 00000000 00000001  //a&b=1

数值在计算机中存储时,都是以补码的形式进行存储的,正整数(包括0)的原码、反码、补码都相同;而负数的原码、反码、补码则需要计算:通过将原码取反再加1,可以得到一个整数的补码;同理将一个补码进行取反加1,也可以得到这个数的原码。

#include<stdio.h>
int main()
{int a = 1;int b = 3;int c = a & b;printf("a=%d,b=%d,c=%d\n", a, b,c);return 0;
}

2.按(二进制)位或  |

规则:对应位只要有一个为1,结果就为1,否则为0。

例如:

int a = 1,b = 3;

00000000 00000000 00000000 00000001  //a

00000000 00000000 00000000 00000011  //b

00000000 00000000 00000000 00000011  //a|b=3

#include<stdio.h>
int main()
{int a = 1;int b = 3;int c = a | b;printf("a=%d,b=%d,c=%d\n", a, b,c);return 0;
}

3.按(二进制)位异或  ^

规则:对应位只有一位为1,结果为1,否则为0。

例如:

int a = 1,b = 3;

00000000 00000000 00000000 00000001  //a

00000000 00000000 00000000 00000011  //b

00000000 00000000 00000000 00000010  //a^b=2

#include<stdio.h>
int main()
{int a = 1;int b = 3;int c = a ^ b;printf("a=%d,b=%d,c=%d\n", a, b,c);return 0;
}

练习:利用异或操作符交换两个变量的值(不创建额外变量)

#include<stdio.h>
int main()
{int a = 1;int b = 3;printf("a=%d,b=%d\n", a, b);a = a ^ b;//2printf("1:a=%d,b=%d\n", a, b);b = a ^ b;//1printf("2:a=%d,b=%d\n", a, b);a = a ^ b;//3printf("3:a=%d,b=%d\n", a, b);return 0;
}

4.按(二进制)位取反:~

假设a的类型是int,a被赋值为1;

a:

原码:00000000 00000000 00000000 00000001

反码:00000000 00000000 00000000 00000001   

补码:00000000 00000000 00000000 00000001   

对其将其按位取反,原来是0的地方变成1,原来是1的地方变成0,那么取反之后则变成了:

~a:

补码:11111111  11111111   11111111  11111110

反码:10000000 00000000 00000000 00000001   //符号位不变,其他位按位取反

原码:10000000 00000000 00000000 00000010  //反码+1,~a = -2

#include<stdio.h>
int main()
{int a = 1;int b = ~a;printf("a=%d b=%d \n", a,b);return 0;
}

注:位操作本身不会改变变量的值,而是创建一个新值,想改变变量的值可以采用:&=、|=、^=、~=。

位操作符用法

1.掩码

按位与运算符常用与掩码(mask)。所谓掩码指的是一些设置为开(1)或关(0)的位组合。

定义一个符号常量MASK为2,其后八位在内存中的形式为00000010,这个MASK称掩码。

再定义一个变量a,赋值为7,其后八位在内存中的形式为00000111。

#include<stdio.h>
#define MASK 2
int main()
{int a = 7;a &= MASK;printf("a=%d\n", a);//a=2return 0;
}

a&MASK = 00000010,最右侧为0号位,最左侧为7号位。在按位与的过程中,除了1号位的1显示了,剩下的所有位都显示为0。这个过程叫做“使用掩码”,因为掩码中的0隐藏了变量a中相应的位。下面是按位与的常见用法:

a &= 0xff;
//或者
a &= 0377;

0xff为16进制,其二进制形式为11111111,八进制形式是0377。这个掩码会保持变量a中的后八位不变,其他位都设置为0。无论a原来是多少位,最终的值都被修改为1个8位字节,8就是该掩码的宽度。

2.打开位(设置位)

有时需要打开一个值中的特定位,同时保持其他位不变。例如:为了打开内置扬声器,必须打开1号位,同时保持其他位不变,这种情况可以用按位或运算符(|)。

设置一个变量a和MASK(只有一号位为1)为例:

假设a为00000111,MASK为00000010,那么a |= MASK =00000111。

MASK中为1的位,a中也为1;MASK中为0的位,a中保持不变。

倘若要同时打开1、3、5号位,那么可以将MASK设置为:00101010,根据不同的需要来设置MASK。

3.关闭位(清空位)

与打开位类似,有时候也需要在不影响其他位的情况下关闭指定位。假设要关闭的变量a中的1号位,可以这样做:

定义符号常量MASK只有1号位为1:00000010

#include<stdio.h>
#define MASK 2
int main()
{int a = 6;printf("改变前:%d\n", a);a &= ~MASK;printf("改变后:%d\n",a);return 0;
}

6的二进制后8位为:00000110

4的二进制后8位为:00000100

MASK中为1的位在结果中清空为0,其他位在结果中保持不变。

位移操作符

位移操作符的操作数只能是整数。

1.左移操作符

规则:左边舍弃,右边补零。

例如:

int a = 5;在C语言中,正整数(包括0)的原码、反码、补码都相同,如下所示:

a:

原码:00000000 00000000 00000000 00000101

反码:00000000 00000000 00000000 00000101   

补码:00000000 00000000 00000000 00000101   

a  << 1:

补码:0 00000000 00000000 00000000 000001010   

右边补一个0,最左边的0抛弃,a << 1的结果为10。

#include<stdio.h>
int main()
{int a = 1;int a2 = a << 1;printf("a=%d,a2=%d\n", a, a2);int b = 5;int b2 = b << 1;printf("b=%d,b2=%d\n", b, b2);return 0;
}

通过测试发现:

  • 左移操作符可以达到*2的效果,左移一位,数值*2;左移两位,数值*4,以此类推。
  • 位移操作符不改变原数值,而是创建了一个可以使用或赋值的新值。

2.右移操作符

规则:右移操作符分为逻辑位移和算数位移两种规则。

逻辑位移:左边补0,右边舍弃。

算数位移:左边补原数值符号位,右边舍弃。

算数位移可以保证新值与原数值的符号相同,较逻辑位移更加科学,大多数编译器都采用此规则。

例如:

int a = -5;

原码:10000000 00000000 00000000 00000101

反码:11111111  11111111   11111111  11111010    //符号位不变,其他位按位取反

补码:11111111  11111111   11111111  11111011    //反码+1得到补码

a >> 1:

补码:11111111   11111111   11111111    11111101 1  //左边补原数值符号位1,右边舍弃1

反码:10000000  00000000  00000000  00000010

原码:10000000  00000000  00000000  00000011   //a>>1 = -3

#include<stdio.h>
int main()
{int a = 1;int a2 = a >> 1;printf("a=%d,a2=%d\n", a, a2);int b = -5;int b2 = b >> 1;printf("b=%d,b2=%d\n", b, b2);return 0;
}

注:对于位移运算符,只有移动正整数位才是有意义的!移动负数、小数等均是标准未定义的,无意义的。

位移操作符用法

1.用位移运算符把整数转换成二进制形式

#include<stdio.h>
#include<limits.h>void itobs(int n, char* ps);//计算二进制
void print_bstr(const char* str);//打印二进制int main()
{printf("请输入数字 or 按其他任意键退出\n");int number = 0;char bin_str[CHAR_BIT * sizeof(int) + 1]={0};//CHAR_BIT表示char中的位数,返回值为8//8 * sizeof(int)为一个整型中的位数,还需要给终止符留位置,再+1while (scanf("%d", &number) == 1)//输入非法字符时跳出循环{itobs(number, bin_str);//计算二进制printf("%d的二进制序列为:>", number);print_bstr(bin_str);//打印二进制putchar('\n');}return 0;
}//计算二进制
void itobs(int n, char* ps)
{int i = 0;const static int size = CHAR_BIT * sizeof(int);for (i = size - 1; i >= 0; i--, n >>= 1){*(ps + i) = (01 & n) + '0';//为了更加贴合计算机,采用01&n,01为8进制序列形式,1&n亦可,//因为数组的形式是char类型,为了表示0或1,还需要加上字符0的值}*(ps + size) = '\0';//最后一个位置赋上终止符
}//打印二进制序列
void print_bstr(const char* str)
{int i = 0;while (*(str + i))//不是空字符{putchar(*(str + i));if (++i % 8 == 0)//为了方便观看,每8个空一格putchar(' ');}
}
  • 上述代码中, CHAR_BIT是头文件<limits.h>中的宏定义,该宏表示char中的位数,返回值为8。
  • 表达式sizeof(int)求一个整型的大小,结果是4个字节;表达式CHAR_BIT * sizeof(int)表示一个整型的位数。
  • 函数itobs中的for循环是从最后一位开始,计算二进制的结果,每次循环结束,n>>1右移一位,进行前一位的计算。
  • 算式01&n的结果只有两种:0或1,为了能在char类型的数组中体现出0、1,还需要将其计算结果加上字符0的大小(‘0’)。
  • 函数中的操作均是利用指针的形式进行运算,所以无需返回值。

最后运算结果如下:

2.转换某一个值的后n位

按位取反操作符可以切换某个值的所有位,但无法切换选中的特定位。假设想切换某个值中的后四位,该如何做?

可以利用按位异或(^)完成这项任务,首先创建一个掩码,然后将掩码的后四位都设置成1,将想更改的值与掩码进行异或操作,便可以切换该数值的后四位了。

int invert(int num, int bits)
{int mask = 0;int val = 1;while (bits-- > 0){mask |= val;val <<= 1;}return num ^= mask;
}
  • 上式中,用num接收想要更改的值,用bits接收想要更改的位数。
  • mask为掩码,val设定为1,将mask与val进行或等操作(|=),可以将mask最后一位更改成1,然后将val左移一个单位,再次进行循环,更改mask倒数第二位的值,以此类推,直到循环结束。
  • 假设bits=4,那么跳出while循环后,mask在计算机存储的值为000011111(后八位),将其与num进行异或,即可切换num后四位的值。

将该函数放到转换二进制例子中,运行结果如下:

通过观察发现,异或操作使后四位的值进行了颠倒。

8.C语言——位操作符与位移操作符相关推荐

  1. 操作符(一)(算数操作符,位移操作符,位操作符)

    目录: 1.算术操作符 2.位移操作符 (1) <<    左移操作符(高位丢掉,低位补0): eg:将1左移1位 (2) >> 右移操作符: eg1:将1右移一位 eg2:将 ...

  2. 【C语言初阶】带你轻松玩转所有常用操作符(1) ——算数操作符,移位操作符,位操作符

    君兮_的个人主页 勤时当勉励 岁月不待人 C/C++ 游戏开发 Hello,这里是君兮_,最近要准备期末复习了,可能更新的就不会那么频繁了,下个星期恢复正常更新. 操作符详解1 前言 一.操作符的分类 ...

  3. 【C语言】第五章 - 操作符

    目录 1.算术操作符 2.移位操作符 左移 右移 3. 位操作符 & 按位与 | 按位或 ^ 按位异或 ~  按位取反 4.赋值操作符 5.单目操作符 6.关系操作符 7.逻辑操作符 8.条件 ...

  4. 一元操作符、强制类型转换表达式、乘除操作符、加法操作符、移位操作符、关系操作符、判等操作符、位操作符与逻辑操作符、条件与操作符、条件或操作符--运算机制与返回值

    操作符处理及返回值 先遣提示 一元操作符 前缀递增操作符 ++ 前缀递增操作符 - - 一元加号操作符 + 关于一元数值提升或二元数值提升 可以看这篇博客 一元减号操作符 - 这里涉及了 原码,反码, ...

  5. 位移操作符 <<左移 与 >>右移 的基本逻辑

    1:<< 左移操作符 2:>> 右移操作符  (注:位移操作符的操作数只能是整数) << 左移操作符   与   >> 右移操作符  都是移二进制位操作 ...

  6. 抽丝剥茧C语言(中阶)操作符+练习

    操作符祥解 导语 操作符分类: 1.算术操作符 2. 移位操作符 2.1 左移操作符 2.2 右移操作符 3. 位操作符 4. 赋值操作符 5. 单目操作符 5.1 单目操作符介绍 5.2 sizeo ...

  7. R语言dataframe创建新的特征(变量)、行加和特征、行均值特征(基于加减乘除、指数、模数等操作符)、创建新的特征(变量)、生成编码特征(基于比较操作符、逻辑操作符)

    R语言dataframe创建新的特征(变量).行加和特征.行均值特征(基于加减乘除.指数.模数等操作符).为dataframe创建新的特征(变量).生成编码特征(基于比较操作符.逻辑操作符) 目录

  8. Java快速入门学习笔记3 | Java语言中的表达式与操作符

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  9. C++语言学习(八)——操作符重载

    C++语言学习(八)--操作符重载 一.操作符重载基础 1.操作符重载的语法 通过operator关键字可以定义特殊的函数,operator本质是通过函数重载操作符. Type operator op ...

最新文章

  1. 三种常见嵌入式设备通信协议
  2. python virtualenv conda_在vscode中启动conda虚拟环境的思路详解
  3. opencv 图像平移、缩放、旋转、翻转 图像仿射变换
  4. CentOS6.7 mysql 主从配置
  5. 如何保持自己 fork 的项目和原始项目同步
  6. 三菱GXWorks2 变换梯形图
  7. maya如何查看资源大纲_干货|Maya入门到精通完全自学教程大纲(建模篇)
  8. 网课答案搜题API接口使用
  9. python 化学反应_有意思的Python:用python配平化学方程式
  10. RemoveWGA升级了
  11. Echarts地图实现点击某地区跳转到指定页面
  12. 毕业了,开始新的生活!
  13. python怎么批量爬取图片_python批量爬取网络图片
  14. 理解深度学习中的学习率
  15. 北京某牧场管理企业——牧场智慧管理项目
  16. 中国无叶片安全风扇市场趋势报告、技术动态创新及市场预测
  17. 数据中心服务器大战:思科vs惠普vs…
  18. String类中的trim()方法实现
  19. Quartus II三种方式实现D触发器及时序仿真
  20. Liunx——文件权限操作

热门文章

  1. c 语言常用的注释方法,注释方法用法 _C语言-w3school教程
  2. iPhone 5 屏幕尺寸变长指南
  3. X79 – E5 1620 1620v2 黑苹果10.15
  4. less @media根据宽度判断不同屏幕手机样式
  5. b460m迫击炮黑苹果_黑苹果简约型娱乐配置
  6. python开源web项目-Python开源项目Top30
  7. 网站服务器 加密狗,致远软件自助服务网站
  8. 卸载删除JDK(详细步骤)
  9. 【强烈推荐】超详解Python-魔法函数(高级语法)
  10. Deep Learning(深度学习)学习笔记整理系列之(七)