• 【初阶C语言】操作符1--对二进制的操作


    前言:本节内容介绍的操作符,操作的对象是二进制位。所以前面先介绍整数的二进制位

    一、二进制位介绍

    1.二进制介绍

    (1)整数的二进制表示形式有三种:原码、反码和补码。

    (2)原码、反码和补码的长度有数据类型来决定,如整数,就是四个字节,转化后是三十二位比特位,所以一个整数写成二进制序列的时候,是32个bit位。

    (3)数据是以补码的形式在内存中存储的。

    (4)正负数原码、反码和补码不一样

    2.正数三码的介绍

    (1)正数的原码、反码和补码都一样,不需要计算,可以直接得出来。

    (2)举例

    7,我们先把7转化成二进制数:111;由于整数的二进制序列是32位,所以其他我需要补0,就写成这样

    原码:00000000 00000000 00000000 00000111

    反码:00000000 00000000 00000000 00000111

    补码:00000000 00000000 00000000 00000111

    3,二进制数为:11  二进制序列:

    原码:00000000 00000000 00000000 00000011

    反码:00000000 00000000 00000000 00000011

    补码:00000000 00000000 00000000 00000011

    3.负数三码的介绍

    我们接下来重点介绍负数的原码、反码和补码

    (1)原码

    对于有符号的整数来说,最高位的一位是符号位;符号位是1表示负数,符号位是0表示正数。若是无符号数,没有符号位,所有位都是有效位。数字0则当成无符号数来看待。

    正数:

    负数:

    对于有符号数来说,正负数原码的差异就是在最高位。

    (2)反码

    1.反码,顾名思义就是取反。

    定义:反码是在原码的基础上,除了符号位,其他按位取反,1的话就写成0,0就写成1。

    2.-7的反码

    原码:10000000 00000000 00000000 00000111

    反码:11111111  11111111   11111111  11111000

    (3)补码

    1.定义:补码则是在反码的基础上+1。

    2.-7的补码

    原码:10000000 00000000 00000000 00000111

    反码:11111111  11111111   11111111  11111000

    补码:11111111  11111111   11111111  11111001

    而补码,就是数据在内存中的存储形式。所以整数在计算的时候使用的也是补码。

    总结:三码的转换规则:原码----(取反)--->反码-----(+1)---->补码

    补码----(-1)--->反码----(取反)--->原码

    补码----(取反,+1)--->原码

    二、移位操作符

    前言:移位操作符包括左移操作符(<<)和右移操作符(>>)

    1.左移操作符(<<)

    (1)常用口诀:左边丢弃,右边补0

    (2)代码演示

    1. #include
    2. int main()
    3. {
    4. int a = 7;
    5. int b = a << 1;//a向左移动一位
    6. printf("%d\n",a);//a的本质没有改变
    7. printf("%d\n",b);
    8. return 0;
    9. }

    代码结果:

    由上面很清楚的就可以知道,其实a的值还是-7,没有改变。

    代码演示2:

    1. #include
    2. int main()
    3. {
    4. int a = -7;//将a的值改成负数
    5. int b = a << 1;
    6. int c = a << 2;
    7. printf("%d\n",a);
    8. printf("%d\n",b);
    9. printf("%d\n",c);
    10. return 0;
    11. }

    运行结果:

    两次代码演示初步总结:左移一位,结果在原数据基础上×2;左移两位,结果在原数据基础上×3;但原数据的值不会改变。

    (3)左移符号解析

    左移符号,移动的是补码,但是打印的时候打印的是原码。

    正数左移:7

    原码:00000000 00000000 00000000 00000111

    反码:00000000 00000000 00000000 00000111

    补码:00000000 00000000 00000000 00000111

    正数的左移比较容易看出来,因为原码、反码和补码都相同

    负数右移:-7

    原码:10000000 00000000 00000000 00000111

    反码:11111111  11111111   11111111  11111000

    补码:11111111  11111111   11111111  11111001

    总结:

        无论正数还是负数,左移的结果都会×2。

    记忆口诀:左边丢弃,右边补0。

    2.右移操作符(>>)

    (1)右移操作符分类

    右移操作符包括:算术右移和逻辑右移

    逻辑右移:右边直接丢弃,左边补0

    算术右移:右边直接丢弃,左边补原符号位(正数补0,负数补1)-----------常用选择

     我们下面的例子也都用算术右移来演示

    (2)代码演示

    1. #include
    2. int main()
    3. {
    4. int a = 10;
    5. int b = a >> 1;
    6. printf("%d\n", a);
    7. printf("%d\n", b);
    8. int c = -10;
    9. int d = c >> 1;
    10. printf("%d\n", c);
    11. printf("%d\n",d);
    12. return 0;
    13. }

    运行结果:

    其实不难发现,算术右移其实也有一种÷2的效果。

    (3)右移图示解析

     

    总结:大多数编译器都是使用算术右移,效果相当于÷2

    算术右移口诀:右边丢弃,左边补原符号位

    3.左移、右移总结

    (1)移动的对象只能是整数

    (2)只能移动正整数位,比如左移一位、右移两位。

    (3)移动后不会改变原数据的值

    (4)移动的是二进制的补码,打印的结果是二进制的原码

    三、位操作符

    前言:位操作符的对象仍然是二进制的补码,他们必须有两个操作对象

    1.按位与(&)

    (1)定义

    两个对象的补码比较,相同位有0则结果位0,相同位都是1结果才为1。

     (2)代码演示

    1. #include
    2. int main()
    3. {
    4. int a = 5;
    5. int b = 7;
    6. int c = a & b;//将按位与的结果赋值给c
    7. printf("%d\n",c);
    8. return 0;
    9. }

     运行结果:

    (3)代码分析

    我们先列出5和7的补码:

    5的补码:00000000 00000000 00000000 00000101

    7的补码:00000000 00000000 00000000 00000111

    图解:

    (4)实列讲解

    根据有0为0,两个1才为1的特点,可以按位与1来确定最低一位(最右一边)是1或者0。

    代码演示:

    1. #include
    2. int main()
    3. {
    4. int a = 3;
    5. int b = a & 1;
    6. printf("%d\n",b);
    7. return 0;
    8. }

    运行结果:

     结果分析:

    3的补码:00000000 00000000 00000000 00000011

    1的补码:00000000 00000000 00000000 00000001

    所以,任何数按位与1,得出的结果为1,则该数的二进制最低为是1,如果是0,则最低为是0。当然,要知道该数的二进制序列的所以1,则需要配合右移符号使用(后续补充)

    2.按位或(|)

    (1)定义

    二进制序列对应位上,有1则为1,两个相同才为0。

    (2)代码演示

    1. #include
    2. int main()
    3. {
    4. int a = 5;
    5. int b = -3;
    6. int c = a | b;//按位或
    7. printf("%d\n",c);
    8. return 0;
    9. }

     运行结果:

    (3)代码解读

    5的补码:00000000 00000000 00000000 00000101

    -3的补码:11111111 11111111 11111111 11111101

    3.按位异或(^)

    (1)定义

    对应的二进制位相同为0,相异为1

    由此而来的知识点:a^a=0          a^0=a

    (2)代码演示

    1. #include
    2. int main()
    3. {
    4. int a = 5;
    5. int b = -3;
    6. int c = a ^ b;//按位异或
    7. printf("%d\n", c);
    8. return 0;
    9. }

    运行结果:

    (3)代码解读

    5的补码:00000000 00000000 00000000 00000101

    -3的补码:11111111 11111111 11111111 11111101

     

    (4)实例讲解

    题目:在不借助第三方变量的情况下,交换两个变量的值

    代码演示:

    1. #include
    2. int main()
    3. {
    4. int a = 520;
    5. int b = 1314;
    6. a = a ^ b;
    7. b = a ^ b;//此时的a=a^b
    8. a = a ^ b;
    9. printf("a=%d b=%d\n",a,b);
    10. return 0;
    11. }

    运行结果:

    代码解读:

    第一步:a=a^b;这个结果先不要算出来

    第二步:b=a^b;这个时候左边的a=a^b,所以整个等式变成b=a^b^b,因为b^b=0,且a^0=a,所以此时就将a的值赋给了b,

    第三步:a=a^b,此时左边的a=a^b,b=a,所以左边=a^b^a=b,所以就将b赋值给了a,完成两个数的交换

     

    四、某些复合赋值操作符和一个单目操作符

    前言:操作对象都是二进制的补码

    1.复合赋值操作符

    (1)赋值操作符的介绍

    >>=    右移等
    <<=    左移等
    &=      按位与等
    |=       按位与等
    ^=      按位异或等

     (2)使用方法

    上面的这些符号就多了一个等号,就如同+=一样

    代码举例:

    1. #include
    2. int main()
    3. {
    4. int a = 5;
    5. a = a >> 1;//普通写法
    6. a >>= 1;//复合写法
    7. a = a << 1;
    8. a <<= 1;
    9. a = a & 2;
    10. a &= 2;//复合写法
    11. a = a | 4;
    12. a |= 4;
    13. a = a ^ 1;
    14. a ^= 1;
    15. return 0;
    16. }

    2.一个单目操作符

    (1)定义:~(一个波浪号)

    作用:对一个数的二进制按位取反

    (2)代码演示

    1. #include
    2. int main()
    3. {
    4. int a = 0;
    5. printf("%d\n",~a);//单目操作符
    6. return 0;
    7. }

    运行结果:

    (3)例子

    1. #include
    2. int main()
    3. {
    4. int a = 10;
    5. a |= (1 << 4);//控制二进制将10变成26
    6. printf("%d\n",a);
    7. //再将26变回10
    8. a &= (~(1 << 4));
    9. printf("%d\n",a);
    10. return 0;
    11. }

    10的补码:00000000 00000000 00000000 00001010

    26的补码:00000000 00000000 00000000 00011010

     10变成26:

     26变回10:只需将该位置按位与上0即可


  • 相关阅读:
    Jenkins学习笔记2
    HttpServletRequest接口详解,获取html用户输入的表单数据,HttpServletRequest请求域,请求转发机制
    Nginx环境搭建、负载均衡测试
    多进程编程
    合封芯片科普,合封技术的实用性
    Linux·内核-硬中断
    XILINX XC7A200T-1FBG676C FPGA - 现场可编程门阵列
    ASP.NET Core 6框架揭秘实例演示[06]:依赖注入框架设计细节
    给网站添加xml地图索引写法
    简述WPF中MVVM的设计思想
  • 原文地址:https://blog.csdn.net/2301_77053417/article/details/132642557