C/C++ 的数据类型表示范围取决于编译器和硬件平台 ,但标准规定了最小范围,实际范围可通过 limits.h 和 float.h 获取。以下以最常见的 32/64 位系统(LP64/ILP32/LLP64) 为准,列出典型范围。
1. 整型(整数类型)
1.1 有符号整型
| 类型 | 位数 | 最小值 | 最大值 |
|---|---|---|---|
signed char |
8 | -128 | 127 |
short (或 short int) |
16 | -32,768 | 32,767 |
int |
32 | -2,147,483,648 | 2,147,483,647 |
long (Linux 64位: 64位; Windows 64位: 32位) |
32/64 | -2,147,483,648 / -9.22e18 | 2,147,483,647 / 9.22e18 |
long long |
64 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
1.2 无符号整型
| 类型 | 位数 | 最小值 | 最大值 |
|---|---|---|---|
unsigned char |
8 | 0 | 255 |
unsigned short |
16 | 0 | 65,535 |
unsigned int |
32 | 0 | 4,294,967,295 |
unsigned long |
32/64 | 0 | 4.29e9 / 1.84e19 |
unsigned long long |
64 | 0 | 18,446,744,073,709,551,615 |
⚠️ 注意 :
char是否有符号由实现定义(通常为signed char,但有些 ARM 工具链默认为unsigned char)。
2. 浮点类型(IEEE 754)
| 类型 | 位数 | 最小值(正) | 最大值 | 精度(有效十进制位数) |
|---|---|---|---|---|
float |
32 | ≈1.175 × 10⁻³⁸ | ≈3.402 × 10³⁸ | 6~7 位 |
double |
64 | ≈2.225 × 10⁻³⁰⁸ | ≈1.798 × 10³⁰⁸ | 15~16 位 |
long double |
80 / 128 (x86扩展精度) | ≈3.36 × 10⁻⁴⁹³² | ≈1.18 × 10⁴⁹³² | 18~19 位 |
特殊值 :
float/double还可表示正负无穷(±INF)、NaN(非数值)、零(有符号零 ±0.0)。
3. 布尔型与字符类型
| 类型 | 取值 | 说明 |
|---|---|---|
bool (C++ / C99) |
true (1) 或 false (0) |
占 1 字节(典型) |
char |
-128~127 或 0~255 | 用于存储 ASCII 或 UTF-8 字节 |
wchar_t |
平台相关(16/32位) | 用于宽字符 |
4. void 类型
void:没有值,不能表示范围。用于无返回值函数或通用指针void*。
5. 如何获取本机的精确范围?
IEEE 754 通过将 S、M、E 编码到固定的二进制位域中来实现存储。
例如:E=127 → 实际指数 0,E=128 → 实际指数 1,E=126 → 实际指数 -1。
(2) 非规格化值(Denormalized / Subnormal)
当 E == 0 且 M ≠ 0 时:
(3) 零值
当 E == 0 且 M == 0 时:
(4) 无穷大(Infinity)
当 E == 255 且 M == 0 时:
(5) 非数值(NaN, Not a Number)
当 E == 255 且 M ≠ 0 时:
3.2 双精度(64 位)
包含头文件 <limits.h> (整型)和 <float.h>(浮点型)。
-
示例:
cpp#include <stdio.h> #include <limits.h> #include <float.h> int main() { printf("int max: %d\n", INT_MAX); printf("double min positive: %e\n", DBL_MIN); return 0; }也可用 C++ 的
<limits>模板:cppstd::numeric_limits<int>::max();6. 标准最低要求(ISO C/C++ 保证)
类型 最小位数 最小值 最大值 signed char8 -127 127 short16 -32,767 32,767 int16 -32,767 32,767 long32 -2,147,483,647 2,147,483,647 long long(C99/C++11)64 -9.22e18 9.22e18 注意:标准允许采用补码 或原码,现代平台全是补码。
任意一个二进制浮点数
V可表示为:V = (-1)ˢ × M × 2ᴱ
-
S:符号位(Sign),0 表示正数,1 表示负数。
-
M:尾数(Significand 或 Mantissa),是一个二进制小数,范围通常为 [1, 2) 或 [0, 1),取决于指数部分。
-
E:指数(Exponent),对尾数进行缩放,可以是正数或负数。
-
IEEE 754 定义了多种浮点格式,最常用的是:
类型 总位数 符号位 指数位 尾数位 指数偏移(Bias) 单精度(binary32) 32 1 8 23 127 双精度(binary64) 64 1 11 52 1023 半精度(binary16) 16 1 5 10 15 四精度(binary128) 128 1 15 112 16383 3.1 单精度(32 位)
cpp[31] 符号位 S [30:23] 指数位 E (8 位) [22:0] 尾数位 M (23 位)表示的值分为几种情况(根据指数 E 的值):
(1) 规格化值(Normalized)
当 0 < E < 255(即 E 不全为 0 也不全为 1)时:
-
实际指数 = E - Bias,Bias = 127。
-
尾数隐含整数部分为 1,即实际尾数 = 1.M(二进制)。
-
因此值 = (−1)S×1.M(2)×2E−127(−1)S×1.M(2)×2E−127。
-
实际指数 = 1 - Bias = -126(固定)。
-
尾数隐含整数部分为 0,即实际尾数 = 0.M。
-
值 = (−1)S×0.M×2−126(−1)S×0.M×2−126。
-
作用:表示非常接近零的数,实现渐进下溢(gradual underflow),避免突然下溢到零。
-
表示 ±0(符号位决定正负零)。正零和负零在算术上通常视为相等。
-
表示 ±∞(符号位决定)。用于溢出结果,如 1.0/0.0。
-
表示未定义或无效的运算结果,如 0.0/0.0,∞ - ∞ 等。
-
可分类为 SNaN (Signaling NaN,会触发异常)和 QNaN(Quiet NaN,不触发异常),通常由 M 的最高位区分。
cpp
[63] 符号位 S
[62:52] 指数位 E (11 位)
[51:0] 尾数位 M (52 位)
Bias = 1023。
-
规格化范围:E 从 1 到 2046,实际指数 = E - 1023。
-
非规格化:E = 0,M ≠ 0,实际指数 = -1022。
-
无穷大:E = 2047,M = 0。
-
NaN:E = 2047,M ≠ 0。
7. 常见陷阱
-
隐式类型转换 :有符号与无符号混合计算时,有符号会被转为无符号,可能导致意外结果(如
-1 > 0U为真)。 -
溢出 :有符号溢出是未定义行为 ;无符号溢出是模 2^n 运算。
浮点数比较
不要直接使用 == 比较两个浮点数,因为累积误差会导致本来相等的值微量不同。应使用:
cpp
fabs(a - b) < epsilon
整数转浮点的精度丢失
当整数超过 2²⁴(单精度)或 2⁵³(双精度)时,无法精确表示所有整数,会产生舍入。
例:16777217 在单精度中会变成 16777216。
运算顺序影响精度
例如 (a+b)+c 与 a+(b+c) 可能因舍入顺序不同导致结果有微小差异。
非规格化数性能问题
有些 CPU 在处理非规格化数时速度较慢(甚至产生异常),可通过设置 FTZ(Flush To Zero)标志强制将非规格化数视为 0 来提高性能(通常在图形或音频处理中)。
*
例题
一个 32位无符号整数可以表示的最大值,最接近下列哪个选项?
A. 4×10^9 [*]
B. 4×10^10
C. 2×10^9
D. 2×10^10
解析 :两种思路,一是 记住32位无符号数的表示范围为0-4,294,967,295,约为4x10**^9;**
-
二是使用更通用的方法。计算一个十进制位需要多少个二进制位,虽然10不能使用整个二进制位表示,但可以按下面的思路推导出来。
-
一个4进制位,可以用2个二进制位表示,因为log2(4)=2
-
一个8进制位,可以用3个二进制位表示,因为log2(8)=3
-
一个16进制位,可以用4个二进制位表示,因为log2(16)=4
-
.....
-
那么一个10进制位,可以用多个少个二进制位表示呢?同样,可以按上面的计算方法,log2(10)≈3.22.
-
32位无符号数可以表示为4x2^30. 30/3.22≈9.316≈9(舍0.316),因此,如果答案在A/B之间,应该选择A。同样,也可以表示成2x2^31. 31/3.22≈9.627≈10(入0.373),如果答案在c/d之间,应该选择D。显然,前者舍0.316,后者入0.373,前者更接近真实值。
32 位 int 类型的存储范围是( )?
A. -2147483647 ~ +2147483647
B. -2147483647 ~ +2147483648
C. -2147483648 ~ +2147483647
D. -2147483648 ~ +2147483648
解析:整数分为无符号数和有符号数,无符号数的范围为0-(2^n-1);有符号的范围为-2^(n-1)-(2^(n-1)-1).最小的负数是-2^(n-1),二进制表示为1000.....0.