程序里写下的数字,看上去只是简单的“值”,但一旦进入内存,实际保存的往往不是我们表面看到的形式。理解类型大小、补码、大小端和 IEEE 754 浮点规则,才能判断一个数在机器里到底是怎么放、怎么取、为什么有时结果又和直觉不一样。本文按“数据类型基础、整数存储、浮点数存储”三步展开,把这些最容易混淆的概念顺下来。
数据类型先解决什么问题
数据类型的意义
数据类型首先决定的是开辟多大的内存空间。空间大小会直接影响这个类型能表示的数值范围,也影响程序如何解释这段内存中的二进制内容。
同样是一串比特位,用不同类型去看,含义可能完全不同。因此,理解“类型”并不只是记名字,更关键的是知道它对应的内存规模和解释方式。
常见类型的基本分类
常见内置类型大体可以分为几类:
- 整形家族
- 浮点数家族:
float、double、long double - 指针类型
- 构造类型
- 空类型:
void
void 空类型通常用于函数返回类型、函数参数以及指针相关场景。虽然它本身不表示具体数值,但在语言层面非常常见。
整数在内存里是怎么存的
原码、反码、补码的关系
计算机中,整数有三种常见的二进制表示方式:原码、反码和补码。三者都包含符号位和数值位两部分,其中符号位用 0 表示正数,用 1 表示负数。

对于正整数来说,原码、反码、补码三者相同;真正需要重点理解的是负整数的表示关系:
原码:就是按照数值的正负直接用二进制的形式表示出来
反码:把原码的符号位不变,其他的位按位取反,即除符号位以外的0变为1,1变为0,得到反码
补码:反码+1得到补码
这里最关键的一点是:对于整数而言,数据存储在内存中,实际存放的是补码,而不是原码。
这也是很多初学者在观察负数二进制结果时容易困惑的原因。源码里写的是一个负数,进内存后却不是按“字面值”直接存,而是转换成补码再保存。
为什么会有大小端
含义:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。
大小端讨论的不是“值变了没有”,而是一个多字节数据在内存地址中的摆放顺序。
之所以会有这个问题,是因为计算机系统按字节编址。每个地址单元对应 1 个字节,而 1 个字节等于 8bit。像 char 通常是 8bit,但 int 往往是 32bit,其他类型也可能更大;不同编译器下,类型大小还可能存在差异。
当处理器寄存器宽度大于 8 位时,比如 16 位或 32 位处理器,一个数据就常常需要拆成多个字节保存。这样就会引出一个必须回答的问题:高位字节和低位字节,谁放低地址,谁放高地址? 大端和小端就是对这个问题的两种不同回答。
因此,理解大小端的关键不是死记定义,而是明确:它只影响多字节数据的存放顺序,不改变数值本身的数学意义。
浮点数在内存中的存储规则
IEEE 754 的基本表示方式
浮点数的存储比整数更复杂。根据国际标准 IEEE 754,任意一个二进制浮点数 V 都可以写成下面的形式:

(-1)^S * M * 2^E
其中:
- (-1)^S 表示符号位,当
S=0时,V为正数;当S=1时,V为负数。 - M 表示有效数字,大于等于 1,小于 2。
- 2^E 表示指数位。
例如十进制的 5.0,写成二进制是 101.0,相当于 1.01×2^2,所以可以得到 S=0,M=1.01,E=2。
十进制的 -5.0,写成二进制是 -101.0,相当于 -1.01×2^2,因此 S=1,M=1.01,E=2。
IEEE 754 规定,对于 64 位浮点数,最高的 1 位是符号位 S,接着 11 位是指数 E,剩下 52 位是有效数字 M。
有效数字和指数为什么要“特殊处理”
IEEE 754 对有效数字 M 和指数 E 还有额外规定,这些规则正是浮点数存储的核心。
先看有效数字 M。因为规范要求 1≤M<2,所以 M 总能写成 1.xxxxxx 的形式,其中 xxxxxx 是小数部分。也正因为第一位总是 1,计算机在内部存储时可以把这一位省掉,只保存后面的部分。
比如保存 1.01 时,实际只存 01,读取时再把前面的 1 补回去。这样做的目的很直接,就是节省 1 位有效数字。以 32 位浮点数为例,原本留给 M 的只有 23 位,省掉前导的 1 之后,等效上就能表示 24 位有效信息。
再看指数 E。它本身按照无符号整数保存。也就是说,如果 E 占 8 位,取值范围是 0-255;如果占 11 位,取值范围是 0-2047。但科学计数法中的指数可以是负数,所以 IEEE 754 规定:存入内存时,必须先给真实指数加上一个中间数。
- 8 位指数的偏移值是 127
- 11 位指数的偏移值是 1023
例如 2^10 的指数是真实值 10,如果保存成 32 位浮点数,就需要写成 10+127=137,也就是二进制 10001001。
指数取出时的三种情况
指数 E 从内存中取出后,并不是统一按一种方式解释,而是分成三种情况:
E不全为0或不全为1:浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
E全为0:浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
E全为1:这时如果有效数字M全为0,表示±无穷大(符号位取决于S)
这一节可以看作理解浮点数行为的关键落点。很多看上去“奇怪”的浮点现象,本质上都来自这里:浮点数不是简单地把小数直接塞进内存,而是按符号位、指数和有效数字三部分编码,再根据不同区间采用不同解释规则。
把这些规则连起来看,就能更清楚地理解两件事:第一,整数和浮点数虽然都存放在内存里,但底层编码逻辑完全不同;第二,程序中的“数值”并不是抽象存在的,它最终一定会落到具体的位模式和存储规则上。









