计算机中数的存储与表示
以C语言、Windows 64位环境为例
考虑这样一个问题:数 3510593 在计算机中是如何存储的?(测试代码放到最后)
整数的存储方式
整数在计算机中采用补码形式存储,存储过程如下:
- 十进制转二进制:3510593的二进制原始形式为:
1101011001000101000001
- 补齐32位:在32位系统中,需补前导零至32位:
00000000001101011001000101000001
- 按字节分割(大端序排列):
00000000 | 00110101 | 10010001 | 01000001
- 十六进制表示:
每4位一组转为十六进制:
0x00 0x35 0x91 0x41
(大端序)
小端序的实际存储
在Windows x64(小端序)环境中,低位字节存放在低地址。因此实际内存布局为:
低地址 -> 高地址:0x41 0x91 0x35 0x00
通过 show_int
输出的结果 41913500
验证了这一点,函数按内存顺序依次打印字节的十六进制值。
浮点数的存储方式
浮点数采用IEEE 754标准,存储过程如下:
- 十进制转二进制科学计数法:3510593 =
1.101011001000101000001 × 2²¹
- 拆分三部分:
- 符号位:0(正数)
- 指数部分:21 + 127(偏移量)= 148 → 二进制
10010100
- 尾数部分:
10101100100010100000100
(截断至23位)
- 完整二进制表示:
0 10010100 10101100100010100000100
- 按字节分割(大端序排列):
01001010 | 01010110 | 01000101 | 00000100
小端序的实际存储
在Windows x64中,浮点数同样按小端序存储:
低地址 -> 高地址:0x04 0x45 0x56 0x4A
通过 show_float
输出的结果 0445564a
验证了这一点,与内存顺序一致。
大端序与小端序的奇妙之处
- 大端序:高位字节存放在低地址,符合人类阅读习惯。
- 小端序:低位字节存放在低地址,便于计算机处理连续进位。
示例对比
数值 | 大端序(逻辑顺序) | 小端序(内存顺序) |
---|---|---|
整数3510593 | 00 35 91 41 |
41 91 35 00 |
浮点数3510593 | 4A 56 45 04 |
04 45 56 4A |
思考
- 最多有几位连续相同?为什么?(提示:IEEE 754标准)
类型 | 二进制 |
---|---|
int | 00000000001101011001000101000001 |
float | 0 10010100 10101100100010100000100 |
测试C语言代码
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
typedef unsigned char *byte_pointer;
typedef unsigned int uint32;
void show_bytes(byte_pointer start, size_t len){
size_t i;
for(i = 0; i < len; i++){
printf("%.2x", start[i]);
}
printf("\n");
}
void show_int(int x){
show_bytes((byte_pointer) &x, sizeof(int));
}
void show_float(float x){
show_bytes((byte_pointer) &x, sizeof(float));
}
void show_pointer(void *x){
show_bytes((byte_pointer) &x, sizeof(void *));
}
void test_show_bytes(int val){
int ival = val;
float fval = (float) ival;
int *pval = &ival;
show_int(ival);
show_float(fval);
show_pointer(pval);
}
void FuncOutputBin(uint32 value)
{
char string[32]={0}; //形参类型uint32最大为32位,因此我这里定义了大小为32的字符串数组存放
itoa(value, string, 2);
// 补齐32位
int len = strlen(string);
printf("库函数得到的二进制为:");
for(int i = 0; i < 32 - len; i++){
printf("0");
}
printf("%s\r\n",string);
}
int main(){
//test_show_bytes(12345);
// int val = 0x87654321;
// byte_pointer valp = (byte_pointer) &val;
// show_bytes(valp, 1);
// show_bytes(valp, 2);
// show_bytes(valp, 3);
// show_bytes(valp, 4);
int val = 3510593;
float valf = (float) val;
show_int(val);
show_float(valf);
//FuncOutputBin(val);
//FuncOutputBin(valf);
return 0;
}