ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

光天化日学C语言(17)- 位运算 ~ 的应用 | 0 变 1、1 变 0

2021-07-08 11:07:20  阅读:188  来源: 互联网

标签:11111111 光天化日 17 int 32 补码 取反 C语言 00000000


????博客主页:https://blog.csdn.net/WhereIsHeroFrom
????欢迎各位 ????点赞 ⭐收藏 ????评论,如有错误请留言指正,非常感谢!
????本文由 英雄哪里出来 原创,转载请注明出处,首发于 ???? CSDN ????
作者的专栏:
  ????C语言基础专栏《光天化日学C语言》
  ????C语言基础配套试题详解《C语言入门100例》
  ????算法进阶专栏《夜深人静写算法》

文章目录

一、前言

  本文作者是从 2007 年开始学 C语言 的,不久又接触了C++,基本就是 C/C++ 技术栈写了 14 年的样子,不算精通,但也算差强人意。著有《夜深人静写算法》系列,且承诺会持续更新,直到所有算法都学完。主要专攻 高中 OI 、大学 ACM、 职场 LeetCode 的全领域算法。由于文章中采用 C/C++ 的语法,于是就有不少读者朋友反馈语言层面就被劝退了,更何况是算法。
  于是,2021 年 06 月 12 日,《光天化日学C语言》 应运而生。这个系列文章主要服务于高中生、大学生以及职场上想入坑C语言的志同道合之人,希望能给祖国引入更多编程方面的人才,并且让自己的青春不留遗憾!
  这一章的主要内容是取反运算符的应用。

二、人物简介
  • 第一位登场的就是今后会一直教我们C语言的老师 —— 光天。
  • 第二位登场的则是今后会和大家一起学习C语言的没什么资质的小白程序猿 —— 化日。
三、取反运算符
  • 取反运算符是一个单目位运算符,也就是只有一个操作数,表示为~x
  • 取反运算会对操作数的每一位按照如下表格进行运算,对于每一位只有 0 或 1 两种情况。
操作数 取反结果
0 1
1 0
#include <stdio.h>
int main() {
    int a = 0b1;
    printf("%d\n", ~a );
    return 0;
}
  • 这里~a代表的是对二进制数 1 进行取反,直观感受应该是 0。
  • 但是实际输出的却是:
-2
  • 这是为什么呢?
  • 那是因为,这是一个 32 位整数,实际的取反操作是这样的:
 ~ 00000000 00000000 00000000 00000001
 --------------------------------------
   11111111 11111111 11111111 11111110
  • 32位整数的二进制表示,前导零也要参与取反。
  • 而对于一个有符号的 32 位整数,我们需要用最高位来代表符号位,即最高位为 0,则代表正数;最高位为 1,则代表负数;
  • 这时候我们就需要引入补码的概念了。

1、补码

  • 在计算机中,二进制编码是采用补码的形式表示的,补码定义如下:

正数的补码是它本身,符号位为 0;负数的补码为正数数值二进制位取反后加一,符号位为一;

2、补码举例

  • 根据补码的定义,-2的补码计算,需要经过两步:
  • 1)对 2 的二进制进行按位取反,如下:
 ~ 00000000 00000000 00000000 00000010
 --------------------------------------
   11111111 11111111 11111111 11111101
  • 2)然后加上 1,如下:
   11111111 11111111 11111111 11111101
 + 00000000 00000000 00000000 00000001
 --------------------------------------
   11111111 11111111 11111111 11111110
  • 结果正好为我们开始提到的~1的结果。

3、补码的真实含义

  • 补码的真实含义,其实体现在 “补” 这个字上,在数学上,两个互为相反数的数字相加等于 0,而在计算机中,两个互为相反数的数字相加等于 2 n 2^n 2n。
  • 换言之,互为相反数的两个数互补,补成 2 n 2^n 2n。
  • 对于 32位整型, n = 32 n = 32 n=32;对于 64位整型, n = 64 n = 64 n=64。所以补码也可以表示成如下形式:
  • [ x ] 补 = { x ( 0 ≤ x < 2 n − 1 ) 2 n + x ( − 2 n − 1 ≤ x < 0 ) [x]_补 = \begin{cases}x & (0 \le x \lt 2^{n-1})\\ 2^{n} + x & (-2^{n-1} \le x \lt 0)\\ \end{cases} [x]补​={x2n+x​(0≤x<2n−1)(−2n−1≤x<0)​
  • 于是,对于int类型,就有:
  • x + ( − x ) = 2 32 x + (-x) = 2^{32} x+(−x)=232
  • 因此, − 2 = 2 32 − 2 -2 = 2^{32} - 2 −2=232−2。
  • 于是,我们开始数数……
2^32        = 1 00000000 00000000 00000000 00000000
2^32 - 1    =   11111111 11111111 11111111 11111111
2^32 - 2    =   11111111 11111111 11111111 11111110
...
四、取反运算符的应用

1、0 的取反

【例题1】0 的取反结果为多少呢?

  • 首先对源码进行取反,得到:
 ~ 00000000 00000000 00000000 00000000
 --------------------------------------
   11111111 11111111 11111111 11111111
  • 这个问题,我们刚讨论完,这个答案为 2 32 − 1 2^{32}-1 232−1。但是实际输出时,你会发现,它的值是-1
  • 这是为什么?
  • 搞得我一头雾水。
  • 原因是因为在C语言中有两种类型的int,分别为unsigned intsigned int,我们之前讨论的int都是signed int的简称。

1)有符号整型

  • 对于有符号整型signed int而言,最高位表示符号位,所以只有31位能表示数值,能够表示的数值范围是: − 2 31 ≤ x ≤ 2 31 − 1 -2^{31} \le x \le 2^{31}-1 −231≤x≤231−1
  • 所以,对于有符号整型,输出采用%d,如下:
#include <stdio.h>
int main() {
    printf("%d\n", ~0 );
    return 0;
}
  • 结果为:
-1

2)无符号整型

  • 对于无符号整型unsigned int而言,由于不需要符号位,所以总共有32位表示数值,数值范围为:
  • 0 ≤ x ≤ 2 32 − 1 0 \le x \le 2^{32}-1 0≤x≤232−1
  • 对于无符号整型,输出采用%u,如下:
#include <stdio.h>
int main() {
    printf("%u\n", ~0 );
    return 0;
}
  • 结果为:
4294967295
  • 即 2 32 − 1 2^{32}-1 232−1。

2、相反数

【例题2】给定一个int类型的正数 x x x,求 x x x 的相反数(注意:不能用负号)。

  • 这里,我们可以直接利用补码的定义,对于正数 x x x,它的相反数的补码就是 x x x 二进制取反加一。即:~x + 1
#include <stdio.h>
int main() {
    int x = 18;
    printf("%d\n", ~x + 1 );
    return 0;
}
  • 运行结果如下:
-18

3、代替减法

【例题3】给定两个int类型的正数 x x x 和 y y y,实现 x − y x - y x−y(注意:不能用减号)。

  • 这个问题比较简单,如果上面的相反数已经理解了,那么,x - y其实就可以表示成x + (-y),而-y又可以表示成~y + 1,所以减法 x - y就可以用x + ~y + 1来代替。
  • 代码实现如下:
#include <stdio.h>
int main() {
    int a = 8;
    int b = 17; 
    printf("%d\n", a + ~b + 1 );
    return 0;
}
  • 运行结果为:
-9

4、代替加法

【例题4】给定两个int类型的正数 x x x 和 y y y,实现 x + y x + y x+y(注意:不能用加号)。

  • 我们可以把x + y变成x - (-y),而-y又可以替换成 ~y + 1
  • 所以x + y就变成了x - ~y - 1,不用加号实现了加法运算。
#include <stdio.h>
int main() {
    int x = 18;
    int y = 7; 
    printf("%d\n", x - ~y - 1 );
    return 0;
}
  • 运行结果为:
25

通过这一章,我们学会了:
  1)按位取反运算符;
  2)补码的运算;
  3)有符号整型和无符号整型;
  4)相反数、加法、减法、等于判定的另类解法;

  • 希望对你有帮助哦 ~ 祝大家早日成为 C 语言大神!

课后习题


????博客主页:https://blog.csdn.net/WhereIsHeroFrom
????欢迎各位 ????点赞 ⭐收藏 ????评论,如有错误请留言指正,非常感谢!
????本文由 英雄哪里出来 原创,转载请注明出处,首发于 ???? CSDN ????
作者的专栏:
  ????C语言基础专栏《光天化日学C语言》
  ????C语言基础配套试题详解《C语言入门100例》
  ????算法进阶专栏《夜深人静写算法》

标签:11111111,光天化日,17,int,32,补码,取反,C语言,00000000
来源: https://blog.51cto.com/u_15239535/3009727

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有