何为大小端字节序,何为整形提升,今天诸君便可一睹芳容。
再C语言知识的海洋中尽情遨游吧,未来的那位顶端程序员。
整数在计算机内存中的储存
这里就简单讲一下这个整形在内存的储存吧,等下我们也是要这个知识点来讲解整形提升。
首先我们就来了解一下计算机中的整数二进制表达方法,其中有原码,反码,补码。
负数的原码补码反码
原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码:原码的二进制中,符号位不变,其它位取反,即可得到反码。
补码:反码+1。即可得到补码。
注:正数的原码补码反码全都相同
而整数在计算机内存中是以补码的形式来存储的,这是为什么呢?
这是因为用补码,可以将符号位和数值域统⼀处理; 同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
运算过程相同是:原码可以符号位不变,其它位取反,再+1得到补码,而补码一样可以取反再+1得到原码。
大小端字节序判断
大端(存储)模式:是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存 在内存的低地址处。
小端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存 在内存的高地址处。
大小端字节序的判断也比较简单,而这两种的不同,是大端还是小端储存在C语言中取决于编译器。那下面我们先看一段代码。
#include <stdio.h> int main() { int a = 0x11223344; return 0; }
一段很简单的代码,0x11223344,为十六进制数11223444,在存储刚好两位数就是一个字节,在这个十六进制数中跟我们平常的个位,十位,百位一样靠右的为低位即44为低位。
这里我们可以通过查看编译器内存的存储方式来判断编译器的存储方式是大端储存还是小端存储。
从上图左边为低地址,往右地址变高,然后我们发现44在低地址处,那么我们就可以判断出在VS中的存储模式为小端模式 。
那么为什么会有大小端之分:
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8 bit 位,但是在C语言中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看 具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和小端存 储模式。
简单来说就是:存储方式的排列方式是区分的,有的机器就是大端,有的就是小端,如人的习惯一样。有人喜欢吃东西加香菜有人不喜欢。
整形提升
这个知识我就用一些代码来边看边了解。我们可以更好了解整形提升。下面是一段代码,认真思考一下哟。
int main() { char a = -1; signed char b = -1; unsigned char c = -1; printf("%d\n", a); printf("%d\n", b); printf("%d\n", c); return 0; }
这里signed char为有符号的char数据,unsiged char为无符号的char数据,那么单单一个char为有符号还是无符号呢,这时还是看我们的编译器的默认情况了,在VS中默认单个char,int等类型数据为有符号的。
回到上面的代码中也就是a和b其实都是一样的数据,且赋值都为-1,那么他们的打印结果也是一样的了。那么他们的打印结果是什么呢,下面我们分析一下
上面列出一步一步的操作:
第一步:列出赋值整数的补码。
第二步:因为char只有1个字节的空间也就是8个bit,所以我们截取低位(靠右边的位置)8个数。
第三步:如果变量要打印出来则先进行整形提升,根据变量类型有无符号提升,有符号则按符号位的数字补全其他高位,无符号类型则高位补0.
第四步:根据printf的占位符打印,%d是以有符号的10进制打印出数据,如果%u则表示以无符号的10进制打印出来。注:打印的就是整形提升得到的数
然后根据上方步骤我们在看看最后一个打印结果的解析:
unsigned char c = -1;
printf("%d\n", c);
这里先是按照第一第二步列出数据补码,截取得到:11111111 ,然后整形提升,这里数据类型为unsigned char;那我们高位补0.得到00000000000000000000000011111111。最后一步以%d打印出结果以有符号的形式打印10进制,这里00000000000000000000000011111111,为正数,补码等于原码打印出来就是255了。我们看一下打印结果。
最后我们再看一段代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() { char a = -128; printf("%d\n", a); printf("%u\n", a); return 0; }
这里也是为了巩固知识,我们还是来按照上面的四步,一步一步来。
第一步:列出整数的补码得到11111111111111111111111110000000。
第二步:然后还是char类型,截取低8位,得到10000000。
第三步:整形提升,符号类型为char,VS默认为有符号,则补高位按符号位1补,得到11111111111111111111111110000000。
第四步:这里有两个打印方式一个是%d,一个是%u,%d为有符号的打印则这里为负数需先把11111111111111111111111110000000变为原码,得到10000000000000000000000010000000然后打印出来为-128.
%u为无符号的打印则这里就会将11111111111111111111111110000000作为原码(正数的原,反,补码相同)打印出来就得到一个很大的数4294967168。
那我们来看一下结果:
这篇文章结束了哟,诸君懂否。