【C语言】整型数据在内存中的存储(详解)
[toc]
数据类型
我们知道,C语言中有很多不同的数据类型
在cppreference.com网站上可以找到C语言中的不同类型【链接】
先来认识一个不那么常见的类型
布尔类型
C99中引入了布尔类型 _Bool
实质:把1和0变成ture和false
1 |
|
代码的效果如下:
因为布尔类型和以1-0来判断正误的作用是相同的
所以这个类型我们一般不会使用
无符号数据的打印
Unsigned无符号数用%u打印
- 用%d打印的时候,认为是有符号数
- 用%u打印无符号数的时候,负数会乱码
我们知道,整型数据在内存中占用4个字节(32位),double类型是8个字节
不同数据占用的字节
在之前的学习中,我们已经知道了如何使用这些不同的数据类型
但是你知道,数据在内存中是怎么存储的吗?
这篇博客将带你认识整型在内存中的存储
整型在内存中的存储
先来认识一下整型家族都有谁吧!
整型家族
char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
我们平时用的最频繁的int其实是signed int
char到底是signed char还是unsigned char,取决于编译器的实现
常见的编译器下,char就是signed char
在知道整型在内存中的存储方式之前
我们需要先认识一下三个好朋友“原 反 补”
“原反补”三兄弟
正整数:原反补码相同
负整数:
原码 | 按照一个数的正负直接写出来的二进制 |
---|---|
反码 | 符号位不变,其他位按位取反 |
补码 | 反码的二进制序列+1,得到补码 |
二进制要怎么写出来呢?
下面以15为例(前面省略了24位)
每一个1都是2的权重
这就是二进制和十进制转换的方式
而15作为正数,原反补码都是这个二进制数
00000000 00000000 00000000 00001111
正数的原反补码相同
什么是符号位?
每一个整型都有4个字节,由32个bit位组成
其中原码的第一位,就是该二进制的符号位
正数为0,负数为1
最高位为符号位,后面的是有效位
再举个-15的例子
10000000 00000000 00000000 00001111 | 原码 |
---|---|
11111111 11111111 11111111 11110000 | 反码 |
11111111 11111111 11111111 11110001 | 补码 |
为了进一步了解数据在内存中的存储方式,我们将15的==补码==转化为十六进制
每4个二进制比特位对应一个十六进制数,转换结果如下
00000000 | 00000000 | 00000000 | 00001111 |
---|---|---|---|
00 | 00 | 00 | 0F |
可当我们在VS编译器-监视-内存窗口里面查看15数据的时候
展示的是以下的16进制形式
可以看到,内存中存储的十六进制,和我们计算出来的是==反着的==
这又是为什么呢?
大小端问题
高位低位来自于人类从左到右的阅读习惯。所以一串二进制数,左侧为高位,右侧为低位
大端字节序存储:
当一个数据的低字节的数据存放在高地址处,高字节序的内容放在了低地址处,这种存储方式就是大端字节序存储
小端字节序存储:
当一个数据的低字节数据存放在低地址处,高字节序的内容放在了高地址处,这种存储方式就是小端字节序存储
简称:小同大异
而我们图中VS内存窗口显示的这种“反着放”的方式,是因为:
- VS编译器下,内存窗口显示的是
左低右高
- 二进制码是
高
00000000 00000000 00000000 00001111低
所以VS编译器是小端存储的
而如果是以低
00 00 00 0f高
的方式放入内存,则是大端字节序存储
负数示例
1 | int b=-10; |
原码10000000 | 00000000 | 00000000 | 00001010 |
---|---|---|---|
反码11111111 | 11111111 | 11111111 | 1110101 |
补码11111111 | 11111111 | 11111111 | 11110110 |
f f | f f | f f | f 6 |
了解了大小端的机制之后,我们可以来写一个简单的函数
判断当前编译器是大端还是小端
1 |
|
这串代码的自定义函数部分可以进行优化
因为*p=1时返回1
其他情况返回0
所以可以选择直接返回*p
1 | //代码优化2 |
进一步优化,我们可以把(char*)&a直接进行解引用并返回他的值
这样就能跳过中间变量p
1 | //代码优化3 |
这里有两个问题需要注意:
不能直接对a进行强制类型转换,这种方式是错的
大小端是把数据放在内存之后才有的现象
大小端讲的是以字节为单位的顺序
char类型只有一个字节,没有大小端问题
为什么整型在内存中存放的是补码呢?
在计算机系统中,数值一般用补码来表示和存储,原因在于,试用补码,可以将符号位和数值域统一处理;
同时,加法和减法也可以统一处理(CPU只有加法器)
此外,补码与反码相互转换,其运算过程是相同的,不需要额外的硬件电路。
计算机中只有加法器,减法用加法来模拟
1-1→1+(-1)
如果用原码的计算:
00000000 00000000 0000000 00000001 | + |
---|---|
10000000 00000000 0000000 00000001 | = |
10000000 00000000 0000000 00000010 | -2 错误 |
补码:
00000000 00000000 0000000 00000001 | 1原 |
---|---|
10000000 00000000 0000000 00000001 | -1原 |
它们的补码
00000000 00000000 00000000 00000001 + | 1的补码 |
---|---|
11111111 11111111 1111111 11111111 = | -1的补码 |
00000000 00000000 0000000 00000000 | 结果为0 |
其中第一个1为符号位
结语
到这里,整型在内存中存储的基本知识就已经讲完啦
如果对你有帮助,还请不要吝啬手里的赞👍!
能留下个评论就更好了
这对我真的很重要!!!