short 和 char 相加结果一定是 int,因 c++ 标准规定位宽小于 int 的整型必须先提升为 int 或 unsigned int,该提升独立于操作数类型,发生在表达式求值前。

short 和 char 相加时结果一定是 int
因为 C++ 标准强制规定:所有位宽小于 int 的整型(如 short、signed char、unsigned char、bool)在参与任何表达式计算前,必须先提升为 int 或 unsigned int。这不是编译器“优化”或“猜测”,而是语言层面的硬性规则。
常见错误现象:short a = 32767; short b = 1; auto c = a + b; —— 此时 c 的类型是 int,不是 short;哪怕你用 decltype(a + b) 查,结果也是 int。
关键点:
- 提升发生在每个操作数上,独立于左右是否同类型;两个
short相加,结果也绝不会是short - 赋值给
short变量时才发生截断,但运算过程本身已在int范围内进行 -
sizeof(a + b)返回的是sizeof(int),不是sizeof(short)
为什么提升目标通常是 int 而不是 short
历史与设计权衡的结果:早期 CPU 对 int 运算最快,对 char 或 short 做算术往往需要额外掩码指令防溢出;统一提升到 int 简化了硬件实现和标准定义。
现代 CPU 上性能差异已不明显,但规则保留是为了向后兼容。真正决定提升目标的是平台上的 int 位宽:
- 在绝大多数系统(
int是 32 位),short(16 位)、char(8 位)都能被int完整表示 → 全部升为int - 仅在极少数老平台(
int是 16 位),unsigned short最大值 65535 >int最大值 32767 → 此时unsigned short会升为unsigned int
有符号和无符号混合时容易踩的坑
整型提升只管“宽度小于 int”的类型;一旦提升完成,后续的算术转换才处理符号混合问题。这意味着两步是分离的:
- 第一步(整型提升):
unsigned char a = 200; unsigned char b = 150;→ 都先升为int(200 和 350) - 第二步(算术转换):此时已是两个
int相加,根本不会触发“无符号转有符号”的危险转换 - 但若写成
unsigned char a = 200; int b = -10;→a先升为int(200),再与b(-10)按int运算,安全 - 而
unsigned short a = 65535; int b = -1;→a升为int后仍是 65535(没溢出),相加得 65534,不是预期的 -2
真正危险的是 int 与 unsigned int 直接混合(比如 int x = -1; unsigned int y = 1; if (x > y) ...),这时才发生“有符号转无符号”的静默转换——那已不属于整型提升阶段。
模板推导和取地址能绕过提升吗
能,但仅限于不触发“值计算”的语境:
-
&a得到的是short*,不是int*;sizeof(short)是 2,但sizeof(a + 0)是sizeof(int) - 模板参数推导:
template<typename t> void f(T); f(a);</typename>→T推导为short(实参是左值,未参与表达式求值) - 但
f(a + b);→a + b是纯右值表达式,已提升为int,所以T是int - 结构体中
short成员仍占 2 字节,但只要一读出来做运算(比如s.x + 1),立刻提升
想“保持 short 运算”没有捷径:用 a += b 是截断回 short,用 static_cast<short>(a + b)</short> 是手动截断,二者都需你自己确保不溢出——提升本身不可禁用,只能接受并应对。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











