整形家族介绍:
整形家族,顾名思义就是囊括了整形类型的家族。那么它包括:
名称 | 类型 | 大小 | 分类 |
int | 整形 | 4字节 | unsigned、signed(有、无符号) |
short | 短整形 | 2字节 | unsigned、signed(有、无符号) |
long | 长整形 | >=4字节 | unsigned、signed(有、无符号) |
long long | 长长整形 | 8字节 | unsigned、signed(有、无符号) |
char | 字符型 | 1字节 | unsigned、signed(有、无符号) |
这里需要对红色字体部分做出解释:
1.long类型的红色部分:long类型的大小根据C语言标准应该为:sizeof(long)>=sizeof(int)。所以,与指针大小类似,在32位平台下大小为4字节;在64位平台下大小为8字节。
2.long long类型的红色部分:long long类型是C99标准新定义的一种类型,可能在许多落后版本的编译器中不能支持C99标准。
3.char类型的红色部分:我们可能会产生这样一种疑问:为什么字符型也能归类为整形家族呢?这是因为ASCLL码值,我们观察ASCLL码表得到: 字符可以转换成对应的数字,数字可以转换成对应的字符。
数据在内存中的存储:
在理解数据在内存是如何存储之前,我们要先了解存储机制。
什么是原码、反码、补码?
数据写成二进制有三种表示方法,分别是:原码、反码、补码。
原码是怎么表示的呢?原码实际上就是数据直接翻译成二进制。
int a=3;//00000000000000000000000000000011
int b=-3;//10000000000000000000000000000011
可以看到3和-3的二进制序列有区别,原因就在于原码、反码、补码是由符号位和数值位组成的。符号位占1个比特位,数值位占31个比特位。
反码、补码怎么得出?
这里我们有对应的计算公式:
原码=数据直接翻译后的二进制序列或者补码符号位不变其他位按位取反然后+1;
反码=原码的符号位不变其他位按位取反。
补码=反码+1;
内存中是如何存储数据的?
我们先上结论:对于整型数据来说,存储在内存中的都是补码。
对于正数:原码、反码、补码相同。
对于负数:需要按照公式进行计算。
那么我们随便定义几个变量,通过编译器的调试-窗口-内存观察:
我们可以看到结果与我们分析的不同。
补码明明是以1010结尾怎么会变成字母a?
这是因为为了方便,计算机会把二进制的补码转换成十六进制,便于我们观察。
每4个二进制位对应一个十六进制位。
十六进制就可以表示为:0x00 00 00 0a
那么我们将二进制转换成十六进制了,那么也是以0a结尾的啊,怎么在内存中是以0a开头的呢?
这就涉及到了存储模式。
大端、小端字节序存储模式
大端字节序存储:把一个数据的高位字节序的内容放在低地址处,把低位字节序的内容放在高地址处。
小端字节序存储:把一个数据的高位字节序的内容放在高地址处,把低位字节序的内容放在低地址处。
而例子中的存储模式是这样的:
由此可以看出啊,我的电脑是小端存储模式的。
我们再次回到例题,看看负数是如何存储在内存中的。
不难发现,我们通过计算,得到的答案能够与编译器匹配。
编写一个程序验证大小端:
#include <stdio.h>
int check()
{
int i = 1;
return *((char*)&i);//将int类型i变量的地址强转为char*类型,解引用时就只能访问一个字节了
}
int main()
{
//定义一个具有返回值变量的检测函数
int ret=check();
//通过返回值判断大小端
if (ret == 1)
printf("小端存储\n");
else
printf("大端存储\n");
return 0;
}
例题详解:
#include <stdio.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("%d %d %d", a, b, c);
return 0;
}
//这串代码输出什么?
变量a我们无法确定是有符号还是无符号的类型,所以暂时不考虑。
变量b是有符号类型的,代码的意思是:将-1赋给有符号的字符类型变量b。
那么计算过程可以是:
现在我们知道变量b里面存的是什么了,但是题目要求我们要用%d即整形的格式来打印。
所以需要进一步分析:
变量b存储的是:11111111,但是通过%d来打印需要整形提升,所以打印的是-1。你猜对了吗?
那么对于无符号的变量c呢?同样是-1赋值给无符号的字符类型变量c,同样是通过%d整形的格式来进行打印。
可以看到,存储的方式是一样的,不同就在于整形提升这里:
如果不明白整型提升,可以翻看我的另一篇专门讲整型提升的博客。
可以看到,整型提升之前和整形提升之后都是正数,所以原码、反码、补码相同,所以打印的是255。
可以看到变量a打印的也是-1,也就说明了,我使用的编译器,默认char类型是有符号的。