整数类型

要使用标准化的整数类型,请始终包含 <cstdint> 和 <cstddef> 头文件:


#include <cstdint>
#include <cstddef> //::std::size_t and ::std::ptrdiff_t are in cstddef

对于 N 位整数: 无符号范围 = 0 到 2^N − 1 有符号范围 = −2^(N−1) 到 2^(N−1) − 1

计算字节数的公式:bytes = N / 8。

位 字节 无符号范围 有符号范围
8 1 0 到 255 -128 到 127
16 2 0 到 65535 -32768 到 32767
32 4 0 到 4294967295 -2147483648 到 2147483647
64 8 0 到 18446744073709551615 -9223372036854775808 到 9223372036854775807
128 16 0 到 340282366920938463463374607431768211455 -170141183460469231731687303715884105728 到 170141183460469231731687303715884105727

最小、最快与精确宽度类型

C++ 定义了三族整数类型:

为什么精确宽度类型可能不存在

精确宽度类型是可选的。在以下情况下它们可能缺失:

在绝大多数平台上这不是问题,但如果你想要最强的可移植性,就应当使用 ::std::int_leastXX_t 与 ::std::uint_leastXX_t。 如果 ::std::uintXX_t 确实存在,那么它保证与 ::std::uint_leastXX_t 相同。

示例


#include <cstdint>
#include <fast_io.h>

int main() {
    using namespace ::fast_io::iomnp;

    ::std::int_least32_t a = -123;   // guaranteed at least 32 bits
    ::std::uint_least64_t b = 1000;  // guaranteed at least 64 bits
    ::std::int_fast16_t c = 42;      // fastest type with ≥16 bits
    ::std::uint8_t d = 255;          // exact 8-bit type (if available)

    println("a = ", a, "\n"          // prints -123
            "b = ", b, "\n"          // prints 1000
            "c = ", c, "\n"          // prints 42
            "d = ", d);              // prints 255
}

最佳实践

浮点类型

要使用标准化的浮点类型,请始终包含 <stdfloat> 头文件:


#include <stdfloat>

浮点数用来表示带小数的实数值。 它们能覆盖极大和极小的量级,但它们是近似的,会引入舍入误差。 与整数不同,浮点数值并不精确。

这些类型依照 IEC 559 标准(也就是 IEEE 754)定义, 该标准规定了浮点数如何表示,以及施加于它们的运算如何表现。

类型 位 字节 近似范围 精度 说明
::std::bfloat16_t 16 2 约 10^±38 约 3 位十进制数字 主要用于 AI/ML 负载,以降低精度换取更快的运算
::std::float16_t 16 2 约 10^±5 约 3–4 位十进制数字 半精度,常见于图形与嵌入式系统
::std::float32_t 32 4 约 10^±38 约 7 位十进制数字 单精度,等价于 float
::std::float64_t 64 8 约 10^±308 约 15–16 位十进制数字 双精度,为了清晰起见优先于 double
::std::float128_t 128 16 约 10^±4932 约 33–34 位十进制数字 四精度,用于高精度科学计算

示例


// Define a reduced-precision floating point (AI/ML)
::std::bfloat16_t bf = 1.5f;

// Define a 16-bit floating point
::std::float16_t f16 = 3.14f;

// Define a 32-bit floating point
::std::float32_t f32 = 2.71828f;

// Define a 64-bit floating point
::std::float64_t f64 = 3.141592653589793;

// Define a 128-bit floating point
::std::float128_t f128 = 1.234567890123456789012345678901234Q;

为什么我们优先选择整数

整数是精确的:它们表示不带舍入的整数。 浮点类型对于科学和数学工作十分强大,但它们可能丢失精度。 用于计数、索引和大小表示时,整数更安全、更可预测。

另一个原因是可移植性:并非所有平台都支持浮点类型。 某些嵌入式系统或特殊环境可能缺少硬件浮点单元,或者模拟得极其缓慢。 即使支持浮点,你也可能受到限制——例如,Linux 内核不允许在内核空间进行浮点运算。 这意味着依赖浮点类型可能降低可移植性,或是在底层编程环境中引发问题。

因此,虽然浮点类型对于科学计算、图形学和机器学习不可或缺, 但整数仍然是通用编程任务中最可移植、最可靠的选择。

传统整数类型

在标准化固定宽度类型(::std::int_leastXX_t、::std::uint_leastXX_t)出现之前, C++ 提供了传统整数类型:char、short、int、long、long long,以及它们的 unsigned 版本。

标准保证了什么

这就是标准的全部保证。它没有固定确切大小。 例如,int 可以是 16 位、32 位、64 位,甚至荒谬的 100000 位——按标准来说依然合法。 这意味着我们不能依赖 int 在各平台上有可预测的大小。

示例


// Traditional integer types

// char is exactly 1 byte. Here we assign it an integer in [0,127],
// which corresponds to ASCII codes (e.g. 97 = 'a', but we will
// explain character literals later).
char c = 97;                 // implementation-defined signedness

short s = 123;               // minimum 16 bits, no larger than int
int i = 456;                 // minimum 16 bits, no larger than long
long l = 789;                // minimum 32 bits, no larger than long long
long long ll = 123456789LL;  // minimum 64 bits

// Unsigned versions
unsigned short us = 123;
unsigned int ui = 1000;
unsigned long ul = 50000;
unsigned long long ull = 100000000ULL;

为什么我们优先选择标准化类型

由于 int、long 等类型的大小除了这些最小值与相对约束之外并无保证, 可移植代码应当使用 ::std::int_least32_t 或 ::std::uint_least64_t 这类标准化类型。 它们在跨平台时提供清晰、可预测的保证。

传统浮点类型

除整数外,C++ 还提供了传统浮点类型: float、double 和 long double。

标准保证了什么

标准没有固定这些类型的确切大小或范围。 它只保证最低精度与次序: 在精度和范围上 float ≤ double ≤ long double。 在大多数现代平台上:

由于标准只规定最低保证,你不能假定确切的大小或格式。 例如,在某些系统上 long double 可能与 double 完全相同,而在另一些系统上它可能提供扩展精度。

示例


// Traditional floating point types

float f = 3.14f;             // at least 6 decimal digits precision
double d = 2.718281828;      // at least as precise as float, usually ~15 digits
long double ld = 1.618033988749894L; // at least as precise as double, may be more

为什么优先使用标准化类型

正如整数一样,传统浮点类型只有最低保证。 为了跨平台的确定行为,现代 C++ 提供了标准化类型,例如 ::std::float32_t、::std::float64_t 和 ::std::float128_t(由 IEC 559 / IEEE 754 标准定义)。 与传统类型不同,它们给出清晰、固定的大小与精度保证。

布尔类型

C++ 提供了专门的逻辑类型:bool。 与整数或浮点类型不同,bool 专门用于表示真值。

标准保证了什么

示例


// Boolean type

bool flag1 = true;    // explicitly true
bool flag2 = false;   // explicitly false

// Conversion from integers
bool b1 = 0;          // becomes false
bool b2 = 1;          // becomes true
bool b3 = 42;         // any non-zero becomes true
bool b4 = -42;        // any non-zero (including negative) becomes true

使用 fast_io 打印


#include <fast_io.h>
#include <cstddef>
#include <stdfloat>

int main()
{
    using namespace ::fast_io::iomnp;

    bool flag = true;

    // Default printing: outputs 0 or 1
    // With boolalpha: outputs textual true/false
    println(flag,        // prints "1"
            " ", 
            boolalpha(flag)); // prints "true"

    // boolalpha also applies to integers and floating point types.
    // Any non-zero value will print as "true", zero prints as "false".
    ::std::size_t i = 42;
    ::std::float64_t d = 0.0;

    println(boolalpha(i),   // prints "true"
            "\n",
            boolalpha(d));  // prints "false"
}

用法

bool 主要用于条件、比较与控制流。 借助 fast_io,你可以用 boolalpha 选择把它打印成 0/1 还是 true/false。 同一个操纵器也可以用于整数和浮点值,把它们解释为逻辑真值。

字符数据类型

C++ 提供了多种字符类型,用于表示不同编码的文本。 虽然 char 最常见,现代 C++ 还引入了 char8_t、char16_t 和 char32_t 以支持 Unicode,另有 wchar_t 表示宽字符。

类型 大小 编码 示例
char 1 字节 由实现定义(通常是 ASCII 或 UTF-8) char c = 'A';
char8_t 1 字节 UTF-8 码元 char8_t u8c = u8'A';
char16_t 2 字节 UTF-16 码元 char16_t u16c = u'A';
char32_t 4 字节 UTF-32 码元 char32_t u32c = U'A';
wchar_t 由实现定义(2 或 4 字节) 宽字符(依平台而定) wchar_t wc = L'A';

#include <fast_io.h>

int main()
{
    using namespace ::fast_io::iomnp;

    char c = 'A';
    char8_t u8c = u8'A';
    char16_t u16c = u'A';
    char32_t u32c = U'A';
    wchar_t wc = L'A';

    // Print numeric values
    println(c);    // prints 65
    println(u8c);  // prints 65
    println(u16c); // prints 65
    println(u32c); // prints 65
    println(wc);   // prints 65

    // Print as characters
    println(chvw(c));    // prints A
    println(chvw(u8c));  // prints A
    println(chvw(u16c)); // prints A
    println(chvw(u32c)); // prints A
    println(chvw(wc));   // prints A
}

重要:所有这些 char 类型在底层仍然都是整数类型。 字面量 'A' 存储为数值 65(它的 ASCII/Unicode 码点)。 这就是为什么调用 println(c) 会打印 65——你看到的是整数值。 要显示字符本身,你需要使用 chvw() 这类操纵器,它们会把整数解释为字符进行输出。

注意:打印 UTF 字符串字面量(u8"..."、u"..."、U"...")时,除非你指定了与字符类型匹配的设备,否则必须使用 code_cvt(...)。 默认情况下,print/println/scan 与 char 和 FILE* 绑定。 我们会在将来的 I/O 章节中详细讲解设备与编码。

附录:ASCII 表(0–127)