您询问的转换是最新的 ISO C 标准第 6.3.1.8 节中定义的常用算术转换和整数提升。它们适用于大多数二元运算符的操作数(“二元”表示它们采用两个操作数,例如+
,*
等)。(规则与 C++ 类似。在此答案中,我将仅参考 C 标准。)
简而言之,通常的算术转换是:
- 如果任一操作数为
long double
,则将另一个操作数转换为long double
。
- 否则,如果任一操作数为
double
,则将另一个操作数转换为double
。
- 否则,如果任一操作数为
float
,则将另一个操作数转换为float
。
- 否则,将在两个操作数上执行整数提升,然后应用一些其他规则将这两个操作数带入公共类型。
整数提升在 C 标准的第 6.3.1.1 节中定义。对于比 窄的类型int
,如果该类型int
可以容纳该类型的所有值,则该类型的表达式将转换为int
; 否则将转换为unsigned int
. (请注意,这意味着类型的表达式unsigned short
可以转换为int
或unsigned int
,具体取决于类型的相对范围。)
当声明未指定参数的类型时,整数提升也适用于函数参数。例如:
short s = 2;
printf("%d\n", s);
short
将值提升到int
。非可变函数不会发生此提升。
为什么要这样做的快速答案是标准是这样说的。
所有这些复杂性的根本原因是允许大多数 CPU 上可用的有限算术运算集。使用这组规则,所有算术运算符(除了移位运算符,这是一种特殊情况)只需要处理相同类型的操作数。没有short + long
加法运算符;相反,short
操作数被隐式转换为long
. 并且对于比int
;窄的类型没有算术运算符。如果添加两个short
值,则两个参数都会提升为int
,从而产生一个int
结果(然后可能会转换回short
)。
一些 CPU 可以对窄操作数执行算术运算,但并非所有 CPU 都可以这样做。如果没有这套统一的规则,编译器将不得不在不直接支持它的 CPU 上模拟窄算术,或者算术表达式的行为会根据目标 CPU 支持的操作而有所不同。当前规则是跨平台一致性和充分利用 CPU 操作之间的良好折衷。