在对象大小与 sizeof 运算符 中,我们指出 C++ 对每种基本类型都规定了最小位宽,而其真实大小可随编译器及目标架构而异。
此灵活性旨在让 int 与 double 等类型能够被设定为在特定架构上性能最优的位宽。例如,32 位计算机通常一次可处理 32 位数据;此时,int 多半被设为 32 位,因为这正是该 CPU 的“自然”数据宽度(也往往是最快的情形)。
提示
数据类型所用的比特数称为其宽度。更宽的类型占更多位,更窄的类型占更少位。
当 32 位 CPU 需要修改一个 8 位值(如 char)或 16 位值时,会发生什么?部分 32 位处理器(如 32 位 x86)可直接操作 8 位或 16 位数据,但速度往往低于 32 位操作;另一些 32 位 CPU(如 32 位 PowerPC)只能操作 32 位数据,必须借助额外技巧来处理更窄的值。
数值提升(numeric promotion)
为在多种架构上兼顾可移植性与性能,C++ 语言设计者不愿假设 CPU 必然能高效处理小于其“自然”数据宽度的值。为此,C++ 定义了一类称为数值提升的类型转换:将某些较窄的数值类型(如 char)转换为较宽且 CPU 能有效处理的类型(通常为 int 或 double)。
所有数值提升均为保值转换(value-preserving conversion,又称安全转换),即源类型的任何可能值都能在目标类型中得到相等值。由于提升是安全的,编译器会按需自动执行且不会给出警告。
数值提升减少冗余
数值提升还解决了另一难题。假设我们要写一个打印 int 的函数:
#include <iostream>
void printInt(int x)
{
    std::cout << x << '\n';
}
若不存在类型转换,为了也能打印 short 或 char,就得再为 short 写一个函数,再为 char 写一个……还得顾及 unsigned char、signed char、unsigned short、wchar_t、char8_t、char16_t、char32_t,很快就会失控。
数值提升拯救了我们:只需编写参数为 int 和/或 double 的函数(如上例的 printInt),即可用任何可被数值提升到这些类型的实参来调用。
数值提升的分类
数值提升规则分为两大类:整型提升(integral promotions)与浮点提升(floating point promotions)。仅列于这两类的转换才被视作数值提升。
浮点提升
较为简单:
根据浮点提升规则,类型 float 的值可转换为类型 double。
因此,可以编写接受 double 的函数,并用 double 或 float 实参调用:
#include <iostream>
void printDouble(double d)
{
    std::cout << d << '\n';
}
int main()
{
    printDouble(5.0);   // 无需转换
    printDouble(4.0f);  // float → double 数值提升
    return 0;
}
第二次调用时,float 字面量 4.0f 被提升为 double,使实参类型与形参匹配。
整型提升
规则更为复杂。按整型提升规则,可进行以下转换:
- signed char或- signed short→- int
- unsigned char、- char8_t、- unsigned short→- int(若- int能容纳该类型全部取值范围),否则 →- unsigned int
- 若 char默认为signed,则遵循signed char规则;若默认为unsigned,则遵循unsigned char规则
- bool→- int,- false变 0,- true变 1
在 8 位字节且 int 至少 4 字节的常见环境下,上述规则意味着 bool、char、signed char、unsigned char、signed short、unsigned short 均被提升为 int。
另有少量更少见的整型提升规则,可参阅 cppreference 相关章节。
多数情况下,我们可编写参数为 int 的函数,并用多种整型实参调用:
#include <iostream>
void printInt(int x)
{
    std::cout << x << '\n';
}
int main()
{
    printInt(2);
    short s{ 3 };      // 无 short 字面量后缀,用变量演示
    printInt(s);       // short → int 数值提升
    printInt('a');     // char → int 数值提升
    printInt(true);    // bool → int 数值提升
    return 0;
}
有两点值得注意:
- 在某些架构(如 int仅 2 字节)上,部分无符号整型可能被提升为unsigned int而非int。
- 某些较窄的无符号类型(如 unsigned char)可能被提升为较宽的有符号类型(如int)。因此,整型提升虽保值,却不一定保留符号性(signed/unsigned)。
并非所有加宽转换都是数值提升
某些加宽转换(如 char → short 或 int → long)在 C++ 中不被视为数值提升,而被归为数值转换(numeric conversions)。原因在于这些转换并不能帮助把较小类型转换为 CPU 更高效处理的大类型。
这一区别多数情况下仅属学术范畴。然而,在特定情形下,编译器会优先选择数值提升而非数值转换。我们将在 —— 函数重载决议与二义性匹配 中看到相关示例。
