精简版 · 小杯2026-08 冻结,已停止更新(发布前修订了 4 处已知错误)。后续勘误与新增内容只在正式版。看正式版(中杯)→
Skip to content

C语言中的数据类型与转换

大纲定位

二(三)整数的表示和运算(1 无符号整数、2 带符号整数)

要求:能在无符号与带符号两种解释之间转换,掌握位扩展与位截断的规则及其保值性。

考情分析

408 的题型只有单项选择题综合应用题两类。本考点以选择题为主,也会作为综合应用题的一环出现(例如循环变量用 unsigned 导致的回绕)。两个原则贯穿始终:位模式不变、解释方式变,以及扩展/截断的方向与顺序

一条最容易失分的规则:C 语言里带符号数与无符号数混在同一个表达式中时,按无符号数运算——这会让 -1 < 0u 为假。

无符号整数与有符号整数

类型编码方式8位范围
无符号整数纯二进制,所有位表示数值0255
有符号整数补码,最高位为符号位128127

同样的 8 位二进制 10000000

  • 作为无符号数解释:128
  • 作为有符号数(补码)解释:128

现代计算机统一用补码表示有符号整数,因为:零的表示唯一、加减法统一为加法、比原码多表示一个最小负数。

C 语言整数类型

类型典型位宽有符号范围无符号范围
char81281270255
short163276832767065535
int32231231102321
long32/64取决于平台取决于平台

未声明 unsigned 则默认为有符号类型。

类型转换的三种情形

1. 相同字长:位模式不变,解释方式变

c
short x = -4321;
unsigned short y = (unsigned short)x;
// x = -4321, y = 61215

x 和 y 的二进制完全相同(0xEF1F),但 x 按补码解释为 4321,y 按无符号解释为 61215

关键规律:n 位有符号数 x(补码)转为无符号数 u

  • x0u=x
  • x<0u=x+2n

所以 (unsigned short)(-1) = 1+216 = 65535

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,解释为 -31071

165537 超出 short 的范围(3276832767),截断后语义完全不同。这种转换不会触发任何错误提示

4. 又改宽度、又改符号性:先扩展,后改解释

这是最容易错的一种,因为两件事同时发生,而顺序是固定的

规则:扩展按"源类型"的符号性做,解释按"目标类型"来

按源类型符号性扩展/截断到目标宽度第一步按目标类型的符号性解释这串位第二步

先看源类型决定怎么补位,再看目标类型决定怎么读。 顺序反过来结果就错了。

c
short si = -32767;
unsigned int ui = si;

一步步走:

做什么结果
0si 是 short,32767 的 16 位补码0x8001
1源类型 short 是有符号 符号扩展到 32 位0xFFFF8001
2目标类型 unsigned int 无符号解释这 32 位23232767
32767=2151ui=232(2151)=232215+1

两个常见错法

错法一:先改解释再扩展。si 先当 unsigned short 读成 21632767=32769,再零扩展 得到 32769。这违反了"扩展按源类型"——si 声明成 short,扩展时它就是有符号的。

错法二:符号写对了但差 1。 算成 232215132767 不是 215,是 (2151),所以是 215+1 而不是 2151。选项里这两个都在。

反向的例子(长转短再转回来):

c
int i    = 32777;     // 0x00008009
short si = i;         // 截断低 16 位 → 0x8009,按 short 读 = -32759
int j    = si;        // si 是 short(有符号)→ 符号扩展 → 0xFFFF8009 = -32759

j=32759,不是 32777——截断丢掉的高位再也回不来了,而截断后最高位恰好是 1,符号扩展只会把它当负数补回去。

记忆钩子:"补位问出身,读数问去向。" 补零还是补符号,看它原来是什么类型;补完之后这串位算多少,看它现在是什么类型。

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

原因:2147483647 的二进制有效位数为 31 位,超过了 float 的 24 位尾数精度,转换时会舍入。

隐式类型提升顺序

charintlongdoublefloat

混合运算时,较低类型自动转换为较高类型。

考点清单

  • 相同字长转换:位模式不变,仅改变解释方式
  • 短→长:有符号做符号扩展,无符号做零扩展
  • 长→短:截断高位,可能导致值完全改变
  • 宽度和符号性同时变时:先按源类型符号性扩展/截断,再按目标类型解释——"补位问出身,读数问去向"
  • (unsigned)(-1) 得到该类型的最大值(全 1)
  • int → float:不溢出但可能丢精度(24 位尾数 < 32 位)
  • int → double:安全(52 位尾数足够)
  • float/double → int:截断小数,可能溢出

真题练习