Ch 7: 基本类型详解
- 掌握整数类型的细节(溢出、无符号)
- 理解浮点数的精度问题
- 学会字符和字符串的处理
- 理解类型的大小和平台差异
7.1 bool 类型
Section titled “7.1 bool 类型”Python 对比
Section titled “Python 对比”# Python - True/Falseis_valid = Trueis_empty = False
# 布尔运算if is_valid and not is_empty: print("OK")
# 布尔值可以参与算术运算result = True + True # 2C++ bool
Section titled “C++ bool”// C++ - true/false(小写)bool is_valid = true;bool is_empty = false;
// 布尔值输出std::cout << std::boolalpha << is_valid; // 输出 "true"std::cout << std::noboolalpha << is_valid; // 输出 "1"
// 布尔值转换bool b1 = 42; // true(非零转为 true)bool b2 = 0; // false(零转为 false)bool b3 = "hello"; // 编译错误!字符串不能转 boolbool 的大小和存储
Section titled “bool 的大小和存储”// bool 的大小是 1 byte(不是 1 bit)std::cout << sizeof(bool); // 1
// 但只能存储 true(1) 或 false(0)bool flag = true;flag = false;
// 布尔值可以参与算术运算(隐式转换)bool a = true; // 1bool b = false; // 0int sum = a + b; // 1
// 算术值转布尔值int x = 1;bool flag2 = x; // true// 逻辑运算符bool a = true, b = false;
bool and_result = a && b; // falsebool or_result = a || b; // truebool not_result = !a; // false
// 短路求值if (ptr != nullptr && ptr->value > 0) { // ptr != nullptr 为 false 时,不执行 ptr->value > 0}
// 注意:运算符重载可能导致不短路7.2 整数类型详解
Section titled “7.2 整数类型详解”| 类型 | 典型大小 | 范围 | 使用场景 |
|---|---|---|---|
int | 4 bytes | -2³¹ ~ 2³¹-1 | 默认整数 |
unsigned int | 4 bytes | 0 ~ 2³²-1 | 位运算、计数 |
long | 4-8 bytes | 平台相关 | 平台原生整数 |
long long | 8 bytes | -2⁶³ ~ 2⁶³-1 | 大整数 |
int8_t | 1 byte | -128 ~ 127 | 精确字节大小 |
int64_t | 8 bytes | 固定 | 跨平台64位 |
# Python - 自动处理大整数(无溢出)x = 2**62x = x * 1000print(x) # 正常计算,无溢出// C++ - 溢出是未定义行为!int i = 2'000'000'000;i += i; // 溢出!int 无法表示 40 亿// 结果:未定义(通常是负数)
// unsigned 溢出是定义行为(回绕)unsigned int u = 4'000'000'000;u += u; // u = 2'147'483'836(回绕到 0)#include <cstdint>#include <stdexcept>
// 安全的整数加法int safe_add(int a, int b) { if (a > 0 && b > INT_MAX - a) { throw std::overflow_error("overflow"); } return a + b;}
// C++20 安全整数// std::signed_arithmetic auto x = 42; // C++26无符号 vs 有符号
Section titled “无符号 vs 有符号”// 不要用无符号做循环计数for (unsigned int i = 10; i >= 0; --i) { // 永远为 true! // i 是 unsigned,不会小于 0}
// 正确做法for (int i = 10; i >= 0; --i) { // 或者for (unsigned int i = 10; i > 0; --i) { // i-- 处理最后一次}7.3 浮点类型详解
Section titled “7.3 浮点类型详解”float vs double
Section titled “float vs double”| 类型 | 大小 | 精度 | Python 对应 |
|---|---|---|---|
float | 4 bytes | ~7 位十进制 | float |
double | 8 bytes | ~15 位十进制 | float(默认) |
long double | 16 bytes | ~34 位 | numpy.float128 |
// 声明和赋值float f1 = 3.14f; // f/F 后缀float f2{3.14f};double d1 = 3.14; // 默认 doublelong double ld = 3.14L; // L 后缀
// 科学计数法double d2 = 1.23e-10; // 1.23 × 10⁻¹⁰double d3 = 6.02e23; // 阿伏伽德罗常数# Python - decimal 模块解决精度from decimal import Decimalresult = Decimal("0.1") + Decimal("0.2") # Decimal('0.3')// C++ - 浮点精度问题#include <iomanip>
double a = 0.1;double b = 0.2;double sum = a + b;
std::cout << sum << std::endl; // 0.30000000000000004std::cout << std::setprecision(20) << sum << std::endl; // 更精确显示
// 比较浮点数if (std::abs(sum - 0.3) < 1e-9) { // epsilon 比较 std::cout << "约等于 0.3" << std::endl;}#include <cmath>#include <limits>
// 无穷大double inf = std::numeric_limits<double>::infinity();
// NaN (Not a Number)double nan = std::nan(""); // Quiet NaN
// 检查if (std::isnan(nan)) std::cout << "是 NaN" << std::endl;if (std::isinf(inf)) std::cout << "是无穷" << std::endl;
// NaN 的诡异行为double result = 0.0 / 0.0; // NaNresult = 1.0 / 0.0; // inf-1.0 / 0.0; // -inf
// NaN 的传播特性double a = std::nan("");double b = a + 1; // 还是 NaN浮点运算的陷阱
Section titled “浮点运算的陷阱”// 不要用 == 比较浮点数double a = 0.1 + 0.2;double b = 0.3;
if (a == b) { // 永远不为 true! // ...}
// 正确做法if (std::abs(a - b) < 1e-10) { // 相等}
// 或者用相对误差bool nearly_equal(double a, double b, double rel_err = 1e-10) { return std::abs(a - b) < rel_err * std::max(std::abs(a), std::abs(b));}7.4 char 和字符
Section titled “7.4 char 和字符”// char - 单个字符(通常是 1 byte = 8 bits)char c1 = 'A';char c2 = 65; // ASCII 值char c3 = '\x41'; // 十六进制char c4 = '\n'; // 转义字符
// 注意:char 可以是有符号或无符号(实现定义)char c5 = 255; // 可能是 -1signed char sc = 255; // 明确有符号unsigned char uc = 255; // 明确无符号
// 输出std::cout << c1; // Astd::cout << (int)c1; // 65ASCII 表
Section titled “ASCII 表”| ASCII | 字符 | 说明 |
|---|---|---|
| 48-57 | 0-9 | 数字 |
| 65-90 | A-Z | 大写字母 |
| 97-122 | a-z | 小写字母 |
// 判断字符类型#include <cctype>
char c = 'A';
if (std::isalpha(c)) {} // 是否字母if (std::isdigit(c)) {} // 是否数字if (std::isalnum(c)) {} // 是否字母或数字if (std::isspace(c)) {} // 是否空白字符if (std::isupper(c)) {} // 是否大写if (std::islower(c)) {} // 是否小写
char upper = std::toupper(c); // 'a' -> 'A'char lower = std::tolower(c); // 'A' -> 'a'| 转义 | 含义 | ASCII |
|---|---|---|
\n | 换行 | 10 |
\t | Tab | 9 |
\r | 回车 | 13 |
\\ | 反斜杠 | 92 |
\' | 单引号 | 39 |
\" | 双引号 | 34 |
\0 | 空字符 | 0 |
// char16_t - UTF-16char16_t c16 = u'中'; // 中文字符char16_t str16[] = u"你好"; // 字符串
// char32_t - UTF-32char32_t c32 = U'中';
// wchar_t - 宽字符(系统相关)wchar_t wc = L'中';wchar_t wstr[] = L"你好";7.5 sizeof 详解
Section titled “7.5 sizeof 详解”#include <iostream>
int main() { std::cout << "基本类型大小:" << std::endl; std::cout << "sizeof(bool) = " << sizeof(bool) << std::endl; std::cout << "sizeof(char) = " << sizeof(char) << std::endl; std::cout << "sizeof(short) = " << sizeof(short) << std::endl; std::cout << "sizeof(int) = " << sizeof(int) << std::endl; std::cout << "sizeof(long) = " << sizeof(long) << std::endl; std::cout << "sizeof(long long) = " << sizeof(long long) << std::endl; std::cout << "sizeof(float) = " << sizeof(float) << std::endl; std::cout << "sizeof(double) = " << sizeof(double) << std::endl; std::cout << "sizeof(long double) = " << sizeof(long double) << std::endl;
// 指针大小(取决于架构) std::cout << "sizeof(int*) = " << sizeof(int*) << std::endl; std::cout << "sizeof(void*) = " << sizeof(void*) << std::endl;
return 0;}sizeof 不计算表达式
Section titled “sizeof 不计算表达式”struct Heavy { std::vector<int> v{1'000'000};};
std::cout << sizeof(Heavy); // 24 bytes(只有指针),不计算 vector 内容!7.6 类型字面量
Section titled “7.6 类型字面量”42 // int42u // unsigned int42L // long42LL // long long42ul // unsigned long42ull // unsigned long long0xFF // 十六进制(255)0b1010 // 二进制(10)C++14010 // 八进制(8)1'000'000 // C++14 数字分隔符3.14 // double3.14f // float3.14L // long double1e10 // 科学计数法1e-5f // float 科学计数法3.14e10L // long double 科学计数法'A' // charL'A' // wchar_tu8'A' // char8_t (C++20)u'A' // char16_tU'A' // char32_t字符串字面量
Section titled “字符串字面量”"hello" // const char[6]u8"hello" // const char8_t[6] (C++20)u"hello" // const char16_t[6]U"hello" // const char32_t[6]L"hello" // const wchar_t[6]R"(raw \n string)" // 原始字符串(不转义)7.7 类型转换详解
Section titled “7.7 类型转换详解”# Python - 自动类型提升result = 3 + 3.14 # 3 转为 3.0,结果是 6.14result = 3 / 2 # 浮点除,结果是 1.5// C++ - 隐式转换规则int i = 3;double d = 3.14;double result = i + d; // i 转 double: 6.14
// 整型提升char c = 'A';int ic = c; // char 转 int: 65
// 截断double dx = 3.99;int ix = dx; // 3,丢失小数部分// static_cast - 编译期可检查的转换double d = 3.14;int i = static_cast<int>(d); // 3
// const_cast - 移除 const 属性const int* pc = &i;int* p = const_cast<int*>(pc); // 移除 const
// reinterpret_cast - 位层面重新解释int* ip = &i;char* cp = reinterpret_cast<char*>(ip); // 把 int* 当 char* 看
// dynamic_cast - 运行时多态转换class Base { virtual void foo() {} };class Derived : public Base {};Base* b = new Derived;Derived* d = dynamic_cast<Derived*>(b); // 安全检查7.8 数值限制
Section titled “7.8 数值限制”#include <limits>#include <climits>
// 整数限制std::cout << INT_MAX << std::endl; // 2147483647std::cout << INT_MIN << std::endl; // -2147483648std::cout << UINT_MAX << std::endl; // 4294967295std::cout << LLONG_MAX << std::endl; // 9223372036854775807
// 浮点限制std::cout << std::numeric_limits<double>::max() << std::endl;std::cout << std::numeric_limits<double>::epsilon() << std::endl;std::cout << std::numeric_limits<double>::infinity() << std::endl;bool是 1 byte,值只能是 true/false- 整数溢出是未定义行为(int),无符号是回绕行为
- 浮点数有精度问题,用 epsilon 比较
char是 1 byte,用单引号- 类型大小:
sizeof(T)返回字节数 - 使用后缀指定字面量类型(
u,L,f,LL) - 四种类型转换:static_cast、const_cast、reinterpret_cast、dynamic_cast
下章预告:ch08 学习字符串处理和 C++20 的 std::format 格式化。