Chapter 3:Dealing with Data

对齐第6版 Chapter 3:按值域与精度选择整数和浮点类型,理解 const、字面量、算术运算、通常转换、显式转换与窄化边界。

学习目标

  • 能比较整数、浮点、字符与布尔类型的值域、精度和语义,并用 sizeof 与 numeric_limits 验证当前实现
  • 能推导混合类型表达式的运算类型、整数除法和 signed/unsigned 比较结果,识别未定义溢出
  • 能设计隐式/显式转换与窄化实验,在赋值前验证源值能否由目标类型表示

机制总览

Chapter 3:Dealing with Data:机制路径

  1. 1

    为什么数据类型是一个可验证的表示选择

    选择类型不是给变量贴标签,而是在声明可表示的值集合、运算规则、精度和错误边界。本章把整数类型、浮点数、const 限定符、算术运算符和类型转换放进同一条数据证据链。人数需要离散且非负,不代表盲目使用 unsigned;金额需要小数,也不代表 binary floating point 能精确表示十进制分币。先写领域范围和允许误差,再选择类型并用实现证据确认。

  2. 2

    整数类型提供离散精确值但范围有限

    short 、 int 、 long 、 long long 至少按该顺序不减小宽度,但标准不保证固定字节数。signed 类型表达正负整数;unsigned 算术按模回绕,但混入 signed 表达式可能把负数转换成巨大无符号值。

  3. 3

    字面量的写法会影响源类型

    整数可用十进制、八进制和十六进制形式,后缀可请求 unsigned、long 等类型;浮点字面量默认是 double, f 后缀表示 float。字符字面量如 'A' 与字符串字面量 "A" 的类型和存储形状不同。

先按顺序建立机制,再进入实验切换阶段并检查失效证据。

章级决策实验

Chapter 3:Dealing with Data:机制与证据

切换《Chapter 3:Dealing with Data》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。

选择推理阶段

当前阶段 · 为什么数据类型是一个可验证的表示选择

选择类型不是给变量贴标签,而是在声明可表示的值集合、运算规则、精度和错误边界。本章把整数类型、浮点数、const 限定符、算术运算符和类型转换放进同一条数据证据链。人数需要离散且非负,不代表盲目使用 unsigned;金额需要小数,也不代表 binary floating point 能精确表示十进制分币。先写领域范围和允许误差,再选择类型并用实现证据确认。

可核验证据

从干净构建开始,以固定输入运行本节示例,再加入一个边界或故障场景验证「为什么数据类型是一个可验证的表示选择」的状态变化。

学完《Chapter 3:Dealing with Data》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。

失效—证据矩阵

Chapter 3:Dealing with Data:失效与核验

为什么数据类型是一个可验证的表示选择

典型失效

若只复述「为什么数据类型是一个可验证的表示选择」结论而不追踪状态、所有权和失败路径,示例扩展成多文件或多对象程序后就容易偏离预期。

核验证据

从干净构建开始,以固定输入运行本节示例,再加入一个边界或故障场景验证「为什么数据类型是一个可验证的表示选择」的状态变化。

整数类型提供离散精确值但范围有限

典型失效

若只复述「整数类型提供离散精确值但范围有限」结论而不追踪状态、所有权和失败路径,示例扩展成多文件或多对象程序后就容易偏离预期。

核验证据

从干净构建开始,以固定输入运行本节示例,再加入一个边界或故障场景验证「整数类型提供离散精确值但范围有限」的状态变化。

字面量的写法会影响源类型

典型失效

若只复述「字面量的写法会影响源类型」结论而不追踪状态、所有权和失败路径,示例扩展成多文件或多对象程序后就容易偏离预期。

核验证据

从干净构建开始,以固定输入运行本节示例,再加入一个边界或故障场景验证「字面量的写法会影响源类型」的状态变化。

每个判断都必须能落到观测、测试或产物,不能只凭代码表面推测。

为什么数据类型是一个可验证的表示选择

选择类型不是给变量贴标签,而是在声明可表示的值集合、运算规则、精度和错误边界。本章把整数类型、浮点数、const 限定符、算术运算符和类型转换放进同一条数据证据链。人数需要离散且非负,不代表盲目使用 unsigned;金额需要小数,也不代表 binary floating point 能精确表示十进制分币。先写领域范围和允许误差,再选择类型并用实现证据确认。

类型选择先回答值域、精度和语义,再用当前实现的 limits 取证;类型名本身不保证固定字节数。

整数类型提供离散精确值但范围有限

shortintlonglong long 至少按该顺序不减小宽度,但标准不保证固定字节数。signed 类型表达正负整数;unsigned 算术按模回绕,但混入 signed 表达式可能把负数转换成巨大无符号值。

#include <iostream>
#include <limits>
 
int main() {
    std::cout << "sizeof(int) = " << sizeof(int) << '\n';
    std::cout << std::numeric_limits<int>::min() << " .. "
              << std::numeric_limits<int>::max() << '\n';
}

若协议需要恰好 32 位,可使用 <cstdint> 中可用的定宽类型;若只是容器大小,常用 std::size_t,但与 signed 下标比较时要显式设计边界。类型选择应附上“为什么这个范围足够”的证据。

字面量的写法会影响源类型

整数可用十进制、八进制和十六进制形式,后缀可请求 unsigned、long 等类型;浮点字面量默认是 double,f 后缀表示 float。字符字面量如 'A' 与字符串字面量 "A" 的类型和存储形状不同。

auto decimal = 42;       // int
auto hexadecimal = 0x2A;
auto large = 42LL;       // long long
auto ratio = 0.5;        // double
auto smallRatio = 0.5F;  // float

不要把进制写法与内存表示混为一谈:420520x2A 表达同一个数值。输出使用哪种格式又是流的表示选择,不会改变对象中的数学值。

浮点类型用有限精度近似实数

floatdoublelong double 以有限位数表示极大范围中的离散近似值。它们可以表示小数和指数范围,但多数十进制小数在二进制中不能有限展开;连续运算会积累舍入误差。

std::numeric_limits<double>::digits10 查看可安全往返的十进制有效位,用 std::setprecision 观察真实存储近似。需要精确分币时可用有界整数表示最小货币单位,或采用明确十进制类型。

const 把不可修改意图交给类型系统

const 限定符要求对象初始化后不能经该名字修改。它适合命名单位换算、边界和只读接口条件;它不是“编译期常量”的同义词,是否可用于常量表达式还取决于初始化和值类别。

const double kilometersPerMile{1.609344};
double miles{12.0};
double kilometers{miles * kilometersPerMile};

命名常量比散落字面量更能表达单位,但仍要检查单位组合。miles * kilometersPerMile 的结果是公里;若变量名缺少单位,类型系统不会自动发现英里和公里混用。

算术结果先由操作数类型决定

两个 int 做 / 得到整数商,小数部分在结果形成前已丢失;之后再赋给 double 只能得到 2.0,无法恢复 5 / 2 被截去的部分。余数 % 用于整数,运算符优先级决定无括号表达式的分组。

double wrong = 5 / 2;              // 2.0
double right = static_cast<double>(5) / 2;  // 2.5

有符号整数结果超出范围是未定义行为,不能先溢出再检查;无符号回绕虽有定义,也不等于业务正确。加法前可判断 a > max - b,或使用经过验证的 checked arithmetic 工具。

通常算术转换发生在目标赋值之前

混合表达式会先执行整数提升和通常算术转换,形成共同类型后再运算。只有结果完成后,才转换到赋值目标。因此诊断应沿字面量、操作数、共同类型、运算、目标类型逐步展开。

转换可能在运算前已经发生;只查看最终赋值类型,会漏掉中间 common type 中的除法、比较与溢出。

显式 static_cast<T> 表达转换意图,但不会自动证明值安全。把 double 转 int 会丢弃小数,把大整数转较小类型可能改变值;应先验证范围,再转换。

列表初始化会拒绝许多可在编译期识别的窄化,例如 int n{3.9};。但运行时值仍需显式检查:来源是 double 变量时,编译器不知道当前值是否落在 int 范围。

小结

  • 整数类型精确表示有限离散集合,实际宽度应以当前实现的 sizeof 和 numeric_limits 取证
  • 浮点类型扩大范围但使用有限精度近似,十进制小数不保证二进制精确表示
  • const 表达只读访问意图;类型、单位和值域仍需要领域契约
  • 算术结果由操作数和通常转换决定,目标赋值发生得更晚,不能修复已经发生的整数除法或溢出
  • 显式转换只说明意图,窄化前仍要验证范围和精度

练习

  1. 问题 1:选择类型。 人口数量、温度测量和精确分币分别需要哪些类型证据?
  1. 问题 2:推导表达式。 为什么 double result = 5 / 2; 得到 2.0,如何得到 2.5?
  1. 问题 3:设计转换闸门。 把用户输入 double 转为 int 数量前要检查什么?

名词解释

名词解释

本章出现的专业名词,用大白话再讲一遍。

可表示范围
类型可表达的最小、最大、步长和特殊值集合。
整数类型
表示有限离散整数集合的内置类型家族。
浮点精度
浮点表示可可靠携带的有效数字和舍入边界。
const 限定符
限制通过特定对象或访问路径修改状态的类型限定。
整数提升
小整数类型在表达式中转换为适合运算类型的规则。
窄化转换
可能丢失源值范围或精度的信息损失转换。

资料与写作方式声明

本章以C++ Primer Plus, Sixth Edition, Chapter 3 Dealing with Data权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…