主页链接: LSR的主页
专栏链接: 《C语言》
文章目录
一、大小端字节序
1. 大小端的定义
大小端字节序(Endianness)是计算机系统中多字节数据在内存中存储的两种不同方式。主要区别在于字节的排列顺序。
大端字节序(Big-Endian):高位字节存储在低地址,低位字节存储在高地址。类似于人类阅读顺序,从左到右由高到低。
小端字节序(Little-Endian):低位字节存储在低地址,高位字节存储在高地址。与人类阅读顺序相反,从右到左由低到高。
记忆口诀:匹配即小端,不匹配即大端。
#include <stdio.h>
int main() {
int num = 1;
char *ptr = (char *)#
if (*ptr == 1) {
printf("Little-Endian\n");
} else {
printf("Big-Endian\n");
}
return 0;
}

2. 为什么会有大小端之分
2.1硬件设计的多样性
不同厂商的处理器(如Intel和ARM)在设计时选择了不同的存储方式:
大端模式(Big-Endian):数据的高位字节存储在低地址。
例如:数值 0x12345678 在内存中的存储顺序为:
12 34 56 78(地址递增方向)。
小端模式(Little-Endian):数据的低位字节存储在低地址。
例如:同一数值存储为:
78 56 34 12(地址递增方向)。
2.2历史与兼容性
大端模式早期被IBM、Motorola等厂商采用,符合人类读写习惯(从左到右高位到低位)。
小端模式由Intel x86架构推广,因低位字节先处理,更适合算术运算(如加法需从低位开始)。
总结:
大小端差异本质是硬件设计自由度的体现,需通过软件或协议(如TCP/IP)解决兼容性问题。
二、整数在内存中的存储
正整数的原、反、补码都相同。
负整数的三种表⽰⽅法各不相同。
原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码。
对于整形来说:数据存放内存中其实存放的是补码,优势就是可以进行数之间的简单运算。
三、浮点数在内存中的存储
常见的浮点数:3.14159、1E10等,浮点数家族包括: float、double、long double 类型。
浮点数表⽰的范围: float.h 中定义
#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;
}

⼗进制的5.0,写成⼆进制是 101.0 ,相当于 1.01×2^2 。
那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2。
⼗进制的-5.0,写成⼆进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
重点在于S,M,E的具体值。
32位:

64位:

1. 存的过程
IEEE 754 对有效数字M和指数E,还有⼀些特别规定。
前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分。
IEEE 754 规定,在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去,只保存后⾯的
xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保
存24位有效数字。
至于指数E,情况就比较复杂
E位数 偏置值 取值范围
8 127 0~255
11 1023 0~2047
E以无符号整数形式存储:8位E取值范围0~255,11位E取值范围0 ~2047
由于科学计数法中E可能为负值,IEEE 754规定存储时需加上偏置值:
8位E加127
11位E加1023
例如:2^10的E=10,存储为32位浮点数时实际存储值为10+127=137(二进制10001001)
2.取的过程
2.1 E有0有1
浮点数的表示遵循以下规则:首先将指数E的计算值减去127(或1023)得到真实值,然后在有效数字M前补上最高位的1。
以0.5为例,其二进制形式为0.1。根据规定,整数部分必须为1,因此将小数点右移1位得到1.0×2^(-1)。此时阶码为-1+127(中间值)=126,对应的二进制表示为01111110。尾数1.0去掉整数部分后为0,补0至23位得到00000000000000000000000。最终其二进制表示形式为:
0 01111110 00000000000000000000000
2.2 E全为0
此时,浮点数的指数E取值为1-127(或1-1023)表示真实值,有效数字M不再需要补上前导的1,而是直接采用0.xxxxxx的小数形式。这种设计可以准确表示±0以及极接近0的微小数值。
0 00000000 00100000000000000000000
2.3 E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
0 11111111 00100000000000000000000
3. 代码分析
我们回到最初的代码上面:
#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;
}
9先以整数形式存储到n中:
0000 0000 0000 0000 0000 0000 0000 1001
如果以整数形式打印,还是9。
如果以浮点数形式打印:
0 00000000 00000000000000000001001
为一个无限接近0的数,所以打印0.000000。
接着9.0以浮点数的形式储存:
首先,浮点数9.0 等于⼆进制的1001.0,即换算成科学计数法是:1.001×2^3
所以: 9.0 = (−1) ^0 * (1.001) ∗ 2 ^ 3 ,那么,第⼀位的符号位S=0,有效数字M等于001后⾯再加20个0,凑满23位,指数E等于3+127=130,即10000010
所以,写成⼆进制形式,应该是S+E+M,即:
0 10000010 00100000000000000000000
以浮点数打印就还是9.0
如果以整数打印:
0100 0001 0001 0000 0000 0000 0000 0000
因为是正数,原码等于补码,即为1091567616。
2180

被折叠的 条评论
为什么被折叠?



