跳转至

类型转换

方法速览

任务 方法 口诀
隐式转换方向 char/shortintunsigned intlong longunsigned long longfloatdouble 小类型让路给大类型
整数提升 char/unsigned char/short/unsigned short 参与运算一律先转 int 比int小的先变int
有符号 ↔ 无符号混算 有符号先转无符号 混算见无符号,负数变巨数
强制转换 (类型)表达式,浮点→整数向零截断 截尾不四舍五入
赋值降级 右侧结果转成左侧类型,超范围回绕 装不下就回绕

隐式类型转换链

同一表达式里出现不同类型时,低位类型自动向高位类型转换(没有信息损失的方向)。本节只讨论这十个类型:

\[\text{char} \to \text{int} \to \text{unsigned int} \to \text{long long} \to \text{unsigned long long} \to \text{float} \to \text{double}\]

unsigned charunsigned shortcharshort 同级,都先提升成 int。)

三条规则:

  • 整数提升charunsigned charshortunsigned short 参与任何运算,先一律转成 int——所以 'a' + 1 的结果是 int 的 98,不是 char
  • 逐级向上intdoubledoublelong longfloatfloat……混合运算的结果类型 = 链上更高的那个;
  • 赋值看左边:运算按链上最高类型算完,存回左边变量时再转成左边类型——装不下就回绕/截断。
表达式 过程 结果类型
'a' + 1 char 提升 int int(98)
5 / 2 全 int int(2)
5 / 2.0 int 转 double double(2.5)
3 + 2.5f int 转 float float
7ll * 2 int 转 long long long long

无符号陷阱:有符号与无符号混算时,有符号一方先转成无符号再算——负数的补码位串直接按无符号解读,变成巨大的正数:

  • (-1) < 1u\(-1\) 转成 \(4294967295\) → 判“假”;
  • unsigned 计数器永远 \(\ge 0\)for (unsigned i = 10; i >= 0; --i) 是死循环——i = 0--i 回绕成最大值,条件恒真。

强制类型转换

写法:(类型)表达式类型(表达式)。转换方向不受链约束,可以往低转——代价是丢信息

  • 浮点 → 整数:向零截断(直接砍掉小数部分,不是四舍五入):(int)3.9 = 3(int)(-3.9) = -3——负数也朝 0 方向砍,不是向下取整(\(-3.9\) 向下取整是 \(-4\),截断是 \(-3\));
  • 大整数 → 小整数:保留低位字节(模 \(2^n\)):char c = 300\(300 - 256 = 44\)
  • double → float:有效位数 16 → 7,精度丢失。

先除后转 vs 先转后除——括号位置决定结果:

1
2
3
4
(int)(3.99 * 10)   → (int)39.9        = 39
(int)3.99 * 10     → 3 * 10           = 30
(double)(5 / 2)    → (double)2        = 2.0
(double)5 / 2      → 5.0 / 2          = 2.5

真题演算

(2019 S 卷):int a = 7; float x = 2.5, y = 4.7;,求 x + a % 3 * (int)(x + y) % 2

步骤 片段 演算 结果
1 (int)(x + y) \(2.5 + 4.7 = 7.2\),向零截断 \(7\)
2 a % 3 \(7 \bmod 3\) \(1\)
3 1 * 7 % 2 同级左结合:\(1\times7=7\)\(7\bmod2\) \(1\)
4 x + 1 int 转 float:\(2.5 + 1.0\) \(3.5\)

答案 \(3.5\)。三处考点:强转只作用于 (x+y) 一个括号;% * 同级左结合;最后 int 与 float 混算提升成 float。

练习题目

练习 1 · 整数提升

题目

cout << 'a' + 1; 输出( )

  • A. b
  • B. \(97\)
  • C. \(98\)
  • D. a1
答案与解析

答案:C

char 参与运算先提升成 int:\(97 + 1 = 98\),按 int 输出。想输出 b 要写 char('a' + 1)

练习 2 · 提升不限于 char

题目

short s = 32767; cout << s + 1; 输出( )

  • A. \(-32768\)
  • B. \(32768\)
  • C. \(32767\)
  • D. 溢出报错
答案与解析

答案:B

short 先提升成 int(4 字节),\(32767+1\) 在 int 里装得下 → 32768。A 是“直接用 short 算”的错误结果——提升让小类型运算不回绕。

练习 3 · unsigned char 提升后存回

题目

unsigned char u = 255; u = u + 1; cout << (int)u; 输出( )

  • A. \(0\)
  • B. \(256\)
  • C. \(255\)
  • D. \(-1\)
答案与解析

答案:A

分两步:u + 1 按 int 算 = 256;存回 u 时转成 unsigned char,\(256 \bmod 256 = 0\)

干扰项思路:B 只看了提升、忘了存回;对比上一题——short 的 32768 装得进 int 所以保留,uchar 的 256 装不进 1 字节所以回绕。

练习 4 · 有符号 char 回绕

题目

char c = 127; c = c + 1; cout << (int)c; 输出( )

  • A. \(128\)
  • B. \(-128\)
  • C. \(127\)
  • D. \(0\)
答案与解析

答案:B

c+1 按 int 算 = 128;存回 char(8 位有符号),位串 10000000补码解读 = \(-128\)

干扰项思路:A 忘了存回时降级。

练习 5 · 超范围赋值截断

题目

char c = 300; cout << (int)c; 输出( )

  • A. \(300\)
  • B. \(-44\)
  • C. 编译错误
  • D. \(44\)
答案与解析

答案:D

300 保留低 8 位:\(300 - 256 = 44\),44 在 \(-128\sim127\) 内 → 44。

练习 6 · 转换链排序

题目

下列类型按隐式转换从低到高排列正确的是( )

  • A. intchardouble
  • B. charintdouble
  • C. doubleintchar
  • D. chardoubleint
答案与解析

答案:B

链:char/short → int → unsigned int → long long → unsigned long long → float → double。

干扰项思路:A、C、D 都把方向搞反或跳级。

练习 7 · 混合运算结果类型

题目

表达式 3 + 2.5 的结果类型是( )

  • A. int
  • B. float
  • C. double
  • D. 无法确定
答案与解析

答案:C

int 遇浮点提升;2.5 这类字面值默认是 double(带 f 后缀才是 float)→ 结果 double。

练习 8 · 5/2 与 5.0/2

题目

cout << 5 / 2 << " " << 5.0 / 2; 输出( )

  • A. 2.5 2.5
  • B. 2 2
  • C. 2.5 2
  • D. 2 2.5
答案与解析

答案:D

5 / 2 全 int → 整数除法得 2;5.0 / 2 时 5 转 double → 2.5。

干扰项思路:A 以为除号自动出小数——两边都是 int 就整除

练习 9 · 整数除法链

题目

cout << 7 / 2 * 2; 输出( )

  • A. \(7\)
  • B. \(6\)
  • C. \(4\)
  • D. \(7.0\)
答案与解析

答案:B

/ * 同级左结合\((7/2)=3\)(整除),\(3\times2=6\)

干扰项思路:A 按先乘后除的直觉算成 7——同级运算从左到右。

练习 10 · 无符号混算

题目

cout << ((-2) < 1u ? "yes" : "no"); 输出( )

  • A. yes
  • B. 编译错误
  • C. no
  • D. 结果不确定
答案与解析

答案:C

\(-2\) 转成无符号:\(-2 + 2^{32} = 4294967294 > 1\) → 判假输出 no。

干扰项思路:A 按数学常识——混算规则先转无符号,负数变巨数。

练习 11 · 无符号循环陷阱

题目

for (unsigned i = 3; i >= 0; --i) cout << i; 循环( )

  • A. 输出 3 2 1 0 后正常结束
  • B. 输出 3 2 1
  • C. 死循环
  • D. 编译错误
答案与解析

答案:C

unsigned 的 i 永远 \(\ge 0\)i = 0--i 回绕成 \(4294967295\)i >= 0 恒真 → 死循环。

干扰项思路:A 忽略回绕;倒序循环要么用 int,要么写 i != UINT_MAX

练习 12 · 向零截断(正数)

题目

cout << (int)3.9; 输出( )

  • A. \(3\)
  • B. \(4\)
  • C. \(3.9\)
  • D. 编译错误
答案与解析

答案:A

浮点转整数向零截断——直接砍小数,不是四舍五入。

练习 13 · 向零截断(负数)

题目

cout << (int)(-3.9); 输出( )

  • A. \(-4\)
  • B. \(3\)
  • C. \(-3.9\)
  • D. \(-3\)
答案与解析

答案:D

向零截断\(-3.9\) 朝 0 的方向砍成 \(-3\)

干扰项思路:A 把“截断”当“向下取整”(floor)——floor 才是 \(-4\)

练习 14 · 括号位置(先转后除)

题目

cout << (double)(5 / 2); 输出( )

  • A. \(2.5\)
  • B. \(2\)
  • C. \(2.0\)
  • D. 编译错误
答案与解析

答案:C

强转只作用于 (5 / 2)结果:先 int 除法得 2,再转 double → 2.0。

干扰项思路:A 以为强转能“挽救”已经丢掉的整数除法——想得 2.5 要写 (double)5 / 2

练习 15 · 括号位置(先转后乘)

题目

(int)3.99 * 10(int)(3.99 * 10) 的值分别是( )

  • A. \(30\)\(39\)
  • B. \(39\)\(30\)
  • C. 都是 \(39\)
  • D. 都是 \(30\)
答案与解析

答案:A

强转优先级高于 *(int)3.99 先截断成 3,再 \(\times10 = 30\);后者先乘出 39.9 再截断 = 39。

练习 16 · char 的字符运算

题目

cout << '5' - '0'; 输出( )

  • A. 50
  • B. \(0\)
  • C. \(5\)
  • D. '5'
答案与解析

答案:C

两个 char 都提升成 int:\(53 - 48 = 5\)——“数字字符转数值”的标准手法。

练习 17 · bool 提升

题目

cout << true + true; 输出( )

  • A. truetrue
  • B. \(2\)
  • C. \(1\)
  • D. true
答案与解析

答案:B

bool 参与算术提升成 int:\(1 + 1 = 2\)

练习 18 · long long 装大和

题目

int a = 1000000000, b = 1000000000; 要正确输出 \(a + b\),应写( )

  • A. cout << a + b;
  • B. cout << (long long)a + b;
  • C. cout << (double)a + b;
  • D. cout << a * 2;
答案与解析

答案:B

\(a+b\) 按 int 算先溢出;先把 a 强转 long long,加法提升成 long long → \(2\times10^9\) 正确。

干扰项思路:A 溢出成负数;C 能装下但整数用浮点会丢精度,不是正解。

练习 19 · sizeof 表达式的类型

题目

sizeof(1 + 1.5) 的值是( )

  • A. \(4\)(int 的大小)
  • B. \(12\)(两者之和)
  • C. 编译错误
  • D. \(8\)(double 的大小)
答案与解析

答案:D

1 + 1.5 的结果类型是 double(提升),sizeof 量的是结果类型的大小 → 8。

练习 20 · float 的存储精度

题目

float f = 16777217; 则 f 实际存储的值是( )

  • A. \(16777217\)
  • B. \(16777216\)
  • C. \(16777218\)
  • D. \(16777200\)
答案与解析

答案:B

float 尾数 24 位,最多精确区分 \(2^{24} = 16777216\) 个整数——\(2^{24}+1\) 是第一个存不下的整数,就近舍入成 \(2^{24}\)

记忆锚点:float 能精确到 1677 万

练习 21 · 赋值降级(浮点→整型)

题目

double d = 3.99; int x = d; cout << x; 输出( )

  • A. \(4\)
  • B. \(3.99\)
  • C. 编译错误
  • D. \(3\)
答案与解析

答案:D

赋值降级:右侧 double 向零截断成 3。

练习 22 · 字符与整数的互换

题目

(char)('A' + 2) 的值是( )

  • A. 'C'
  • B. 'B'
  • C. \(67\)
  • D. 'A2'
答案与解析

答案:A

'A' = 65\(65+2 = 67\),强转回 char → 'C'

干扰项思路:C 忘了强转回 char(那是 ('A'+2) 不加转换的输出)。

练习 23 · 表达式的中间截断

题目

int x = 9; double y = x / 4; cout << y; 输出( )

  • A. \(2.25\)
  • B. \(2\)
  • C. \(3\)
  • D. \(2.5\)
答案与解析

答案:B

x / 4 两边都是 int → 整除得 2,赋给 double 变 2.0。右边已经是截断后的值,左边接不住丢掉的小数。

干扰项思路:A 以为赋给 double 就会按小数除——先除后转,顺序不能反。

练习 24 · 累加器类型

题目

double s = 0; s += 1 / 3; s += 1 / 3; s += 1 / 3; cout << s; 输出( )

  • A. \(1\)
  • B. \(0\)
  • C. \(0.999999\)
  • D. \(0.333333\)
答案与解析

答案:B

每个 1 / 3 都是 int 整除 = 0,加三次还是 0。想得 1.0 要写 1.0 / 3

干扰项思路:D 把每次整除想成 0.33……——int 除法在表达式内部就截断了,轮不到 double 接。

练习 25 · 强转与取模综合

题目

int t = (int)7.9 + 9 % 4; cout << t; 输出( )

  • A. \(8\)
  • B. \(9\)
  • C. \(10\)
  • D. \(11\)
答案与解析

答案:A

优先级:强转 > %(3 级)> +(4 级)——(int)7.9 = 79 % 4 = 1\(7 + 1 = 8\)

干扰项思路:B 把 7.9 四舍五入成 8 再加 1(或忘了截断按 7.9 + 1 估)——截断不四舍五入

练习 26 · 综合求值

题目

cout << 3 + 4 / 2.0 + (int)2.9; 输出( )

  • A. \(7\)
  • B. \(8\)
  • C. \(8.5\)
  • D. \(7.5\)
答案与解析

答案:A

分步:4 / 2.0 → double 除法 = 2.0;(int)2.9 截断 = 2;\(3 + 2.0 + 2 = 7.0\)cout 输出 7

干扰项思路:C 把 (int)2.9 当 3、又把 4 / 2.0 当 2.5(\(3+2.5+3=8.5\));B 把 4 / 2.0 当整除 2、(int)2.9 当 3(\(3+2+3=8\))。

历年真题

2019 年 · S 卷第 1 题

题目

若有定义:int a=7; float x=2.5, y=4.7;,则表达式 x+a%3*(int)(x+y)%2 的值是:( )

  • A. 0.000000
  • B. 2.750000
  • C. 3.500000
  • D. 2.500000
答案与解析

答案:C

演算见上文“真题演算”节:(int)(x+y) 截断成 7,a%3=11*7%2=12.5+1=3.5。强转只管一个括号、%/* 同级左结合、最后提升成 float——三步都不能错。

2024 年 · 第 8 题

题目

在 C/C++ 中,(char)('a'+13) 与下面的哪一个值相等?( )

  • A. 'm'
  • B. 'n'
  • C. 'z'
  • D. '3'
答案与解析

答案:B

'a' = 97,先提升成 int 加 13 得 110,强转回 char → 'n'(97 是 a,110 是 n——a 到 m 差 12,到 n 差 13)。

干扰项思路:A 差一位(a+12 才是 m)——ASCII 数到字符时极易偏一。

易错小结

  • 提升方向char/shortintunsignedlong longfloat/double;小类型运算先升 int,升完不回绕,但存回小类型时会回绕char c = 300 → 44);
  • 无符号陷阱:混算负数变巨数;unsigned 计数器写 i >= 0 是死循环;
  • 截断 ≠ 四舍五入(int)3.9 = 3(int)(-3.9) = -3——负数朝 0 砍,不是 floor;
  • 强转只管紧挨着的操作数(double)(5/2) 是 2.0,(double)5/2 才是 2.5——括号位置改变一切;
  • 整除发生在表达式内部x / 4 两边都 int 就先整除,赋给 double 也接不回小数;
  • 大数加法先转 long long(long long)a + b,别让 int 先溢出;
  • 浮点字面值默认 double3 + 2.5 的结果类型是 double,不是 float。