2024-07-16 笔记- 2
如何理解 【数据截断】 +【 整型提升】???
在这之前可以先理解一下大小端字节序存储,之前写过关于这个的一部分笔记。
大小端字节序存储
通俗一点讲,就是,数据存放不开,只能取出部分二进制位数,其余的二进制位数就丢弃掉,丢弃掉的那一部分就是截断。
【 数据截断 】
在之前学习的内容中,我也知道了【整型家族】在计算机中都是按照【补码】存储的
So
截断,是对【补码】进行截断,而不是【源码】。(一定别搞错了,对于正数来说确实无所谓,因为正数的源码,反码,补码都是一样,但是对于负数来说,可就不一样了,源码和补码不一样,可千万别搞错)
下面说一下到底如何对补码进行截取,截取以后又是怎么存到对应类型的变量中去的。
1) 以 int 的数据存到 char 中为例(int –> char)
char a = -1; //数据截断 存储
printf("%d", a);//整型提升 打印
如上代码,如果想要将 int 的 -1 存储到 char 中,相当于大的数据存到小的空间中,此时就要进行截断。
2) 那么如何进行截断呢???
先将 10 进制的数值 转换成 2 进制的,方便理解。
因为【整型家族】的类型都是以补码的形式进行存储的,所以要将源码转换成补码(正数源码、反码、补码相同)。
源码 - 10000000 00000000 00000000 00000001
反码 - 11111111 11111111 11111111 11111110
补码 - 11111111 11111111 11111111 11111111
^ ^
【 截断 】【 取出 】--> 11111111(补码)
3) 知道了补码以后,截断的时候截断的时候留的哪一部分,丢弃的哪部分???
- 首先将所需要的【低位字节】11111111取出;(最右侧的), 然后丢弃剩余的【高位字节】;
- 将取出的11111111存储到 int 的 a 中
在这就要注意了:
-
如果存储到signed(有符号) char ,
11111111
的最高位就是**【符号位】,那么不具有【数值意义】,也就不会参与计算,作用只有一个,即表示正负** -
如果存储到unsigned(无符号) char,
11111111
的最高位就是【数值】,具有**【数值意义】**,会参与计算。
那么这个11111111
是补码,表示的什么数值???
先将补码变成源码,就能求出来了
char a = -1;种的 a: 补码 - 11111111 取反 - 10000000 + 1 - 10000001 //--> -1
4) 疑惑???截断和 大小端有关系吗???
没有关系,
截断是先将数据进行截断,然后再存储到内存中的。
和大小端字节序存储没有关系,即和按照什么顺序存储到内存中没有什么关系。
截断就是丢弃掉数据的【高位字节】
【整型提升】
整型提升有
两种
- signed 的是一种
- unsigned 的是一种
这两种采用的方式不一样的。
1) signed char –> int (两种补法)
如果【原数据】的符号位是1,高位字节全部补1
如果【原数据】的符号位是0,高位字节全部补2
有点抽象,下面举例说明
在signed char中存储的 11111111负数
signed char a 中 a 的数据是11111111,要存到 int(int类型的数据占4字节,4 * 8bit) 中11111111进行整型提升,才能存储到int中去,因为符号位为1,所以前面所有的高位字节全部补1
11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 高位字节 低位字节 在signed char中存储的是 00001111正数
signed char a 中 a 的数据是00001111,要存到 int(int类型的数据占4字节,4 * 8bit) 中00001111进行整型提升,才能存储到int中去,因为符号位为0,所以前面所有的高位字节全部补0
00000000 00000000 00000000 00001111 高位字节 低位字节 补码 - 11111111 11111111 11111111 11111111 取反 - 10000000 00000000 00000000 00000000 + 1 - 10000000 00000000 00000000 00000001 --> -1
2) unsigned –> int
unsigned char 中,二进制数中,开头一位是具有数值意义的。
【原数据】如果是无符号的,那么无论开头是1还是0,【高字节】统一都补0
因为开头的二进制数,并不是戴代表的符号。
有点抽象,下面举例说明
01111111
01111111 – > 00000000 00000000 00000000 01111111
00000000 00000000 00000000 01111111 高位字节 低位字节 10000000
10000000 – > 00000000 00000000 00000000 10000000
00000000 00000000 00000000 10000000 高位字节 低位字节
剩下的还没学,明天再记笔记吧~
2024-07-17
下面用一个例子进行举例,再解释一遍,也为了加深自己的印象~
问题:输出的什么???
为了再一步巩固,【数据截断】和【整型提升】,下面用题来解释明白。
#include <stdio.h> int main() { char a = -1; signed char b = -1; unsigned char c = -1; printf("a = %d, b = %d, c = %d", a, b, c); return 0; } //-1 -1 255
这一步为【截断】
-1 源码 - 10000000 00000000 00000000 00000001 反码 - 11111111 11111111 11111111 11111110 补码 - 11111111 11111111 11111111 11111111 ^ ^ 【 截断 】【 取出 】--> 11111111(补码) - 内存中存补码 char a 为有符号, 将 11111111(补码) 存入 a 中,开头1为符号位,表示负数 signed char a 为有符号, 将 11111111(补码) 存入 b 中,开头1为符号位 unsigned char a 为无符号, 将 11111111(补码) 存入 c 中,在这计算机不认为开头1不是符号位,它具有数值意义。
这一步为【整型提升】
下方为【整型提升】以后存的数据。
char a; 11111111 --整型提升--> 11111111 11111111 11111111 11111111(补码) - 内存中存补码(无论是补什么,第一位就是符号位) 10000000 00000000 00000000 00000000(取反) - 符号位不变,其余取反 10000000 00000000 00000000 00000001(+1 得到源码) - //-1 signed char a; 11111111 --整型提升--> 11111111 11111111 11111111 11111111(补码) - 内存中存补码(无论是补什么,第一位就是符号位) 10000000 00000000 00000000 00000000(取反) 10000000 00000000 00000000 00000001(+1 得到源码) - //-1 unsigned char a; // (谨记,这里存的补码就不需要转换成源码去求值了,因为对于unsigned来说,补码就是源码) 11111111 --整型提升--> 00000000 00000000 00000000 11111111(补码 == 反码 == 源码) - 内存中存补码 - //255
下面是运行的具体结果
笔记就先记到这里吧,小白一个,可能很多地方不对哈哈,希望网友们提出错误的地方。向网友们学习。