Appearance
C语言中的数据类型与转换
大纲定位
二(三)整数的表示和运算(1 无符号整数、2 带符号整数)
要求:能在无符号与带符号两种解释之间转换,掌握位扩展与位截断的规则及其保值性。
考情分析
408 的题型只有单项选择题和综合应用题两类。本考点以选择题为主,也会作为综合应用题的一环出现(例如循环变量用 unsigned 导致的回绕)。两个原则贯穿始终:位模式不变、解释方式变,以及扩展/截断的方向与顺序。
一条最容易失分的规则:C 语言里带符号数与无符号数混在同一个表达式中时,按无符号数运算——这会让
-1 < 0u为假。
无符号整数与有符号整数
| 类型 | 编码方式 | 8位范围 |
|---|---|---|
| 无符号整数 | 纯二进制,所有位表示数值 | |
| 有符号整数 | 补码,最高位为符号位 |
同样的 8 位二进制 10000000:
- 作为无符号数解释:128
- 作为有符号数(补码)解释:
现代计算机统一用补码表示有符号整数,因为:零的表示唯一、加减法统一为加法、比原码多表示一个最小负数。
C 语言整数类型
| 类型 | 典型位宽 | 有符号范围 | 无符号范围 |
|---|---|---|---|
| char | 8 | ||
| short | 16 | ||
| int | 32 | ||
| long | 32/64 | 取决于平台 | 取决于平台 |
未声明 unsigned 则默认为有符号类型。
类型转换的三种情形
1. 相同字长:位模式不变,解释方式变
c
short x = -4321;
unsigned short y = (unsigned short)x;
// x = -4321, y = 61215x 和 y 的二进制完全相同(0xEF1F),但 x 按补码解释为
关键规律:
- 若
: - 若
:
所以 (unsigned short)(-1) =
2. 短类型 → 长类型:位扩展
| 源类型 | 扩展方式 | 规则 |
|---|---|---|
| 有符号数 | 符号扩展 | 高位填充符号位 |
| 无符号数 | 零扩展 | 高位填充 0 |
c
short x = -4321; // 0xEF1F
int y = x; // 符号扩展 → 0xFFFFEF1F,值仍为 -4321
unsigned short u = 61215; // 0xEF1F
unsigned int v = u; // 零扩展 → 0x0000EF1F,值仍为 61215符号扩展保持数值不变(补码的性质),零扩展保持无符号值不变。
3. 长类型 → 短类型:截断
直接丢弃高位,仅保留低位。截断可能导致数值完全改变。
c
int x = 165537; // 0x000286A1
short y = (short)x; // 截断为 0x86A1,解释为 -310714. 又改宽度、又改符号性:先扩展,后改解释
这是最容易错的一种,因为两件事同时发生,而顺序是固定的:
规则:扩展按"源类型"的符号性做,解释按"目标类型"来
先看源类型决定怎么补位,再看目标类型决定怎么读。 顺序反过来结果就错了。
c
short si = -32767;
unsigned int ui = si;一步步走:
| 步 | 做什么 | 结果 |
|---|---|---|
| 0 | si 是 short, | 0x8001 |
| 1 | 源类型 short 是有符号的 | 0xFFFF8001 |
| 2 | 目标类型 unsigned int |
两个常见错法
错法一:先改解释再扩展。 把 si 先当 unsigned short 读成 si 声明成 short,扩展时它就是有符号的。
错法二:符号写对了但差 1。 算成
反向的例子(长转短再转回来):
c
int i = 32777; // 0x00008009
short si = i; // 截断低 16 位 → 0x8009,按 short 读 = -32759
int j = si; // si 是 short(有符号)→ 符号扩展 → 0xFFFF8009 = -32759记忆钩子:"补位问出身,读数问去向。" 补零还是补符号,看它原来是什么类型;补完之后这串位算多少,看它现在是什么类型。
int 与 float/double 的转换
| 转换方向 | 可能发生的问题 |
|---|---|
| int → float | 不溢出,但可能精度丢失(int 32 位有效位 > float 24 位尾数) |
| int → double | 安全(double 52 位尾数,足以精确表示 32 位 int) |
| float → double | 安全(精度和范围都扩大) |
| double → float | 可能溢出(超出 float 范围)或精度丢失 |
| float/double → int | 小数部分截断(向零取整),可能溢出 |
例:int → float 精度丢失
c
int n = 0x7FFFFFFF; // 2147483647,二进制有效位 31 位
float f = (float)n; // float 尾数只有 23+1=24 位,需舍入
int m = (int)f; // m 可能不等于 n原因:
隐式类型提升顺序:
混合运算时,较低类型自动转换为较高类型。
考点清单
- 相同字长转换:位模式不变,仅改变解释方式
- 短→长:有符号做符号扩展,无符号做零扩展
- 长→短:截断高位,可能导致值完全改变
- 宽度和符号性同时变时:先按源类型符号性扩展/截断,再按目标类型解释——"补位问出身,读数问去向"
(unsigned)(-1)得到该类型的最大值(全 1)- int → float:不溢出但可能丢精度(24 位尾数 < 32 位)
- int → double:安全(52 位尾数足够)
- float/double → int:截断小数,可能溢出