类型转换
复习提示(中优先级):类型转换的关键是判断位模式是否变化,以及目标类型能否完整表示源值。
常在选择题考查,其实就 三点:整形和浮点数的转换,不同长度类型的转换,隐式和显式的转换。
有符号整数和无符号整数
当 有符号整数 和 无符号整数 之间相互转换时,二进制数据 不变,只是改变了变量(或数字)的类型。
首先需要了解 有符号整数(int)和 无符号整数(unsigned)这两个类型:
int:使用 补码 来存储数据。unsigned:所有位,包括最高位,都用于表示数值,表示非负数。
注意:C 语言只规定各整数类型的最小宽度和相对大小,具体位宽由实现决定。常见平台的
int与unsigned int都是 32 位;实现提供相应类型时,int32_t、uint32_t可明确表示恰好 32 位的有符号和无符号整数。
这里为了方便说明,以 8 位 有符号整数 和 无符号整数 为例:
- 8 位 有符号整数
- 表示的范围为
-128 ~ 127 - 最大数为
127,对应的二进制为0111 1111 - 最小数为
-128,对应的二进制为1000 0000
- 表示的范围为
- 8 位 无符号整数
- 表示的范围为
0 ~ 255 - 最大数为
255,对应的二进制为1111 1111 - 最小数为
0,对应的二进制为0000 0000
- 表示的范围为
当 int 和 unsigned 进行 类型转化 时,位模式 不变,可以理解成计算机存储单元中的二进制表示没有变化,只是从程序层面阐述该二进制数据的方式变了,如下图所示:
整数和浮点数
在计算机中,整形(short, int, long)和 浮点数(float, double)之间可以相互转换,但是在转换的过程中可能出现 精度丢失 或 数据溢出。
整数转浮点数
如果一个整数被转换为浮点数,其结果是否会产生 精度丢失 取决于整数的大小是否超过浮点数可以精确表示的整数范围。 但当整数足够大时,转换可能导致 精度损失。
例如 IEEE 754 单精度 float 的 frac 字段为 23 位,加上隐含的最高位后,有效精度为 24 位。因此区间 内的每个整数都能被精确表示,若一个 int 的值在这个范围内,转换为 float 时不会丢失精度。
超出这个范围并不意味着一定无法精确表示:较大的 2 的整数次幂及某些低位为 0 的整数仍可精确表示。能否精确表示取决于该数量级下相邻浮点数的间隔;不能落在可表示点上的整数会被舍入。
浮点数转整数
当 浮点数 被转换为 整数 时,小数部分会丢失,因为 整数 不能表示小数。
此外,如果 浮点数 超出了 整形 的表示范围,转换可能会 溢出 或产生未定义行为(取决于语言)。
不同长度的类型转换
| 类型 | C 标准规定的最小位数 | 常见 ILP32 | 常见 LP64 | 常见 LLP64 |
|---|---|---|---|---|
char |
8 | 8 | 8 | 8 |
short |
16 | 16 | 16 | 16 |
int |
16 | 32 | 32 | 32 |
long |
32 | 32 | 64 | 32 |
long long |
64 | 64 | 64 | 64 |
float |
— | 32 | 32 | 32 |
double |
— | 64 | 64 | 64 |
其中 ILP32 常见于 32 位系统,LP64 常见于 64 位 Unix-like 系统,LLP64 常见于 64 位 Windows。表中浮点位宽是主流 IEEE 754 实现的常见值。
总结一下不同长度的 整数 和 浮点数 的 类型转换 规则:
- 整数和整数
- 较小的整数类型转换为能覆盖其全部取值范围的较大整数类型时,无符号数进行零扩展,有符号补码进行符号扩展,不会丢失数值。
- 较大的 整数类型 被转换为较小的 整数类型 时,高位会被自动截断,可能有数据丢失。
- 浮点数和浮点数
float转为double时,不会有 精度丢失,double转为float时,可能有 精度丢失。
以 short 和 int 的类型转化为例说明:
/* 将 short 转为 int */
short s = 0x1234;
int i = s;
// 高 16 位被填充为 0
// i = 0x00001234
/* 将 int 转为 short */
int i = 0x12345678;
short s = i;
// 高 16 位被截断
// s = 0x5678
隐式与显式类型转换
在编程中,类型转换 指的是将一种数据类型转换为另一种数据类型。主要分为两种:
- 隐式类型转换(Implicit Type Conversion)(也称为 类型提升,Type Promotion)
- 显式类型转换(Explicit Type Conversion)(也称为 强制转换,Type Casting)
隐式类型转换
在 C 语言中,当算术运算、赋值和比较表达式中涉及的多个变量类型不同时,如果没有显式指定类型,编译器会自动进行 类型转换。
/* 隐式类型转换 */
int i = 5;
float f = 2.5;
float result = i + f; // i 被隐式转换为 5.0 然后进行计算
在一个表达式中混合使用 int 和 float 时,C 语言通常会把 int 转换为 float 后再计算。这里的“类型等级更高”不保证数值精度一定更高:大整数转为 float 仍可能被舍入。
显式类型转换
也可以使用 类型转换运算符 显式地转换一个类型为另一个类型。
/* 显式类型转换 */
int i = 5;
float f = 3.2;
int result = (int)f + i; // f 被显式转换为 3,然后与 i 相加
显式类型转换 会按照你指定的方式进行,在此过程中可能会发生 精度缺失。
位模式、数值解释与转换风险
同一组 位的比特可以有不同解释。按无符号整数解释时范围是 到 ;按补码有符号整数解释时范围是
因此“重新解释位模式”和“进行数值转换”不是一回事。最高位为 1 的位模式按无符号解释是较大的正数,按补码解释则可能是负数;没有移动任何 bit,数值含义却已改变。混合有符号、无符号运算时,应先按语言或题设的提升规则统一类型,再比较或计算,不能仅凭变量原来的数学值判断结果。
扩大整数位宽时,无符号数通常在高位补 0,有符号补码数通常做符号扩展,即复制原符号位;两种扩展都应保持原数值。缩小位宽时,高位被截去,结果可能溢出原类型可表示范围;对无符号位模式可看作模 保留低位,而有符号结果的具体语义还需遵循 ISA 或语言规则。做位扩展题时先写出原位模式,再写新增或保留哪些位,比直接心算十进制更不易出错。
整数转浮点数需要把值规格化为尾数和指数;当整数有效位超过浮点尾数字段能精确表示的范围时,低位会按舍入规则丢失。浮点数转整数通常去掉小数部分,但 NaN、无穷大或超出目标整数范围时的结果取决于处理器和语言环境,不能一概说成“截断后一定得到某个正常整数”。转换题应分别检查符号、范围、精度和舍入四件事。