目录
引言
c语言常用的内置数据类型有整型,字符型,浮点类型,研究他们的存储方式虽然不能直接帮助我们提高代码能力,但也好比修炼内功,一定会使我们对程序更有“掌控感”.接下来,我们将从大小端顺序到整型,字符型,最后到浮点类型,为大家分享数据在内存中的存储等相关问题。
1. 大小端顺序
1.1 定义
我们都知道,计算机访问数据一般都是以字节为单位的,一个字节包括8个比特位,可以存储256个不同的数据。但如果是超过了一字节的数据1,通常就设计到了大小端的顺序,比如十六进制0x11223344在内存中的存放。
所谓大端排序,就是高字节的部分(11),放在低地址处,低字节的部分(44),放在高字节处。
所谓小端排序,就是高字节的部分(11),放在高地址处,低字节的部分(44),放在低地址处。
1.2 检验的方法
在不同的编译器下,可能会采取不同的排序方式。那么如何查看呢?这里有两种方法供大家思考。
1. 调试
可以通过调试,调用内存窗口,如在vs2022,x64的环境下,int类型的储存就是小端排序的。
2. 代码
#define _CRT_SECUR_NO_WAENINGS 1
#include<stdio.h>
int check(int* p)
{
return *((char*)p);
}
int main()
{
int x = 1;
int ret = check(&x);
if (ret)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
计算机中每个字节都有一一对应的地址,而超过1个字节的数据,比如int,4个字节,取出的地址是地址最小的那个,也就是低地址。
我们可以取出x(1),再强制类型转换成char*,再解引用,我们就可以得到数据在低地址处的值,1的值高字节位00,低字节位01,解引用出来,是哪个,就是哪个。
2. 整型在内存中的存储
整型在内存中存放数据时都是以二进制的补码进行存储的。有符号无符号都一样的
如 -666在内存中的存储
原码:0000 0000 0000 0000 0000 0010 1001 1010
反码:1111 1111 1111 1111 1111 1101 0110 0101
补码:1111 1111 1111 1111 1111 1101 0110 0110
十六进制:0xFFFF FD66
小端存放: 66 FD FF FF
3. 字符及数组在内存中的存放
3.1 字符
字符在内存中的二进制的值在ASCII 码表 - cppreference.com中变可以查到。
字符‘a’的ASCLL值为97
97 的16进制为61
左边表示的是值,右边表示的是对应的ASCLL字符
3.2 数组
我们需要记住,数组中的成员在内存中是由低地址到高地址连续存放的
如“abcdefg”,a在低地址,g在高地址
4. 浮点数在内存中的存放
4.1 存放规则

这是浮点数在内存中存储的标准。
4.2 举例
比如浮点数-173.8125
// 转换成二进制(整数部分:除2取余,逆序排列,小数部分:乘2取整,顺序排列)
二进制为:-1010 1101.1101
// 二进制101(6)= 1.01 * 2^2 前面是二进制,后面是十进制表示,这样做,是为了方便
// 因为我们要的就是他的指数位,指数位其实就是小数点移动的位数
转换成科学计数法-1.010 1101 1101 * 2^7
由于是负数: (-1)^1 * 1.010 1101 1101 * 2^7
S = 1
M = 1.010 1101 1101
E = 7
单精度32位浮点数float
双精度64位浮点数double
以上便是浮点数在内存中的存储排序方式,也就是我们的S,M,E的排列存放方式。由低地址到高地址分别是S,M,E。
关于M
在科学计数法中M一定是1.xxxxx,不要觉得0.8125就会0开头了,二进制为0.1101,转换后就是1.101 * 2 ^-1,M就是1开头的。——因次默认这个数的第⼀位总是1,因此可以被舍去,只保存后⾯的 xxxxxx部分。⽐如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样做的⽬ 的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保 存24位有效数字.
⾄于指数E,情况就⽐较复杂⾸先,E为⼀个⽆符号整数(unsigned int) 这意味着,如果E为8位,它的取值范围0~255;如果E为11位,它的取值范围为0~2047。但是,我 们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存⼊内存时E的真实值必须再加上 ⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。⽐如,2^10的E是 10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
-173.8125 S,M,E 转换1 1000 0110 010 1101 1101 000000000000
1100 0011 0010 1101 1101 0000 0000 0000
C3 2D D0 00
小端排序后 :00 D0 2D C3
4.3 读取规则
4.3.1 E不全为0或不全为1
正常翻译即可。
调试看到:00 D0 2D C3
换位置:C3 2D D0 00
展开:1100 0011 0010 1101 1101 0000 0000 0000
S = 1 M = 1.010 1101 1101 E = 7
值= -173.8125
4.3.2 E全为0或全为1
如果E全为0,这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还 原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字。
如果E全为1,这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);
5 练习
#include <stdio.h>
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}
结果:
n的值为:9
*pFloat的值为:0.000000
num的值为:1091567616
*pFloat的值为:9.000000