附录B 其他源代码
还原apue.h公共头文件与标准错误处理例程,形成全书示例可编译、可诊断的共同底座。 覆盖3个正式目录层级。
为什么从接口合同开始
、、、、共同构成本页坐标。还原apue.h公共头文件与标准错误处理例程,形成全书示例可编译、可诊断的共同底座。
APUE第3版面向SUSv4/POSIX.1-2008,并以Solaris 10、Mac OS X 10.6.8、FreeBSD 8.0和Ubuntu 12.04为主要验证平台。正文先还原书中标准合同与实现差异;Linux当前行为只能作为显式现代对照,不能悄悄覆盖原书的版本边界。
六阶段可重放链
1. 定义公共头
围绕apue.h记录平台、功能测试宏、输入、描述符/对象表、返回值、errno和预期状态。进入“声明错误API”前保存第一条偏离,清理与恢复也写入结果。
2. 声明错误API
围绕标准错误例程记录平台、功能测试宏、输入、描述符/对象表、返回值、errno和预期状态。进入“格式化上下文”前保存第一条偏离,清理与恢复也写入结果。
3. 格式化上下文
围绕errno记录平台、功能测试宏、输入、描述符/对象表、返回值、errno和预期状态。进入“保留errno”前保存第一条偏离,清理与恢复也写入结果。
4. 保留errno
围绕可变参数记录平台、功能测试宏、输入、描述符/对象表、返回值、errno和预期状态。进入“链接示例”前保存第一条偏离,清理与恢复也写入结果。
5. 链接示例
围绕构建底座记录平台、功能测试宏、输入、描述符/对象表、返回值、errno和预期状态。进入“运行失败样本”前保存第一条偏离,清理与恢复也写入结果。
6. 运行失败样本
围绕apue.h记录平台、功能测试宏、输入、描述符/对象表、返回值、errno和预期状态。进入“定义公共头”前保存第一条偏离,清理与恢复也写入结果。
机制、所有权与失败模型
还原apue.h公共头文件与标准错误处理例程,形成全书示例可编译、可诊断的共同底座。
本页核心不变量是:公共声明只有一个来源,错误例程保留errno并区分退出与返回;构建无隐式声明和重复符号。 它必须同时约束正常、边界、故障和恢复样本。接口返回成功只是证据之一,还要检查短计数、EINTR/EAGAIN、对象继承、并发时序、缓冲与异步清理。
实验台账至少包含平台与版本、编译宏、入口参数、对象所有者、描述符或ID、预期返回、实际返回、errno、首个状态分叉、原始轨迹和清理结果十一列。性能样本还需固定预热、CPU放置、输入规模、采样窗口与分位数;信号/线程样本必须记录掩码、取消状态和处理上下文。
附录使用法:从查表到可执行证据
附录不是正文之外的速查碎片。第一次使用附录B 其他源代码时,先从当前问题反向定位apue.h与标准错误例程,抄录标准声明、所需头文件、功能测试宏和返回约定;然后回到对应正文章节确认对象由谁创建、谁继承、谁关闭。这样能避免只记函数名却丢失标准条件,也能发现同名接口在C库封装、系统调用和不同UNIX实现之间的责任差异。
第二步建立最小构建。创建只包含一个入口、一个成功样本和一个失败样本的小目录,开启C11、全部常见告警并把告警视为错误。编译输出必须保存编译器版本、宏展开结果、链接符号和运行平台;如果需要apue.h或公共错误例程,只链接同一份实现,不能通过复制粘贴制造多个略有差异的版本。此时重点不是“程序能跑”,而是声明、定义、调用约定和错误报告能互相对上。
第三步验证失败合同。分别制造不存在的路径、权限不足、短输入、信号中断、容量耗尽和并发关闭,只保留与当前接口相关的一个变量。记录原始返回值后立刻保存errno,随后再格式化诊断;否则后续库调用可能覆盖真正首错。对于返回指针、描述符、PID或线程ID的接口,还要写清失败前后所有权是否发生转移,以及清理函数在部分初始化状态下能否安全执行。
第四步做实现对照。至少比较标准文本保证、书中四个平台观察和当前Linux实测三列:标准未规定的行为标为“实现选择”,运行时可查询的限制保留查询结果,编译期选项保留宏值。不能因为两台Linux机器结果相同就把它提升为POSIX规则,也不能因为历史平台接口仍可编译就假设它适合新代码。
第五步把答案接回正文证据链。定义公共头、声明错误API、格式化上下文、保留errno、链接示例、运行失败样本不是六个孤立动作,而是一条从前提到恢复的闭环。每个结论都附最小程序、构建命令、原始标准输出/错误、系统调用轨迹、资源清单和清理结果;复核者无需依赖作者机器的隐藏状态即可得到相同基线,并能在单变量故障下看到相同第一处分叉。
最后做反例审查:删掉一个头文件、改变一个功能测试宏、让一个调用返回短计数、在错误打印前插入会改errno的函数、或让子进程在exec前走一条不安全路径。若测试仍然“通过”,说明断言只检查了最终文本而没有约束接口合同。修正断言后关闭描述符、join线程、wait子进程、删除IPC名字并恢复信号与终端属性,再以同一输入重放;只有无残留地回到基线,附录知识才真正进入工程能力。
最后再做一次陌生环境复核:清空构建产物与临时环境变量,在新shell或最小容器中仅按记录执行。若仍需口头补充路径、权限、输入文件或清理顺序,说明实验合同尚不完整;把这些隐含前提写入台账,重新抓取原始输出并核对资源数归零。
可重放命令骨架
cc -std=c11 -Wall -Wextra -Werror -Iinclude src/*.c -o probenm -g probe | sort
readelf -Ws probe | sed -n '1,20p'make clean && make check
find . -type f -name '*.o' -delete正式目录逐项讲解
附录B 其他源代码
“附录B 其他源代码”不是孤立API名词。把对象、控制流、失败模型、原始证据和恢复条件收束为可复查清单,并用同一输入重放确认没有残留状态。在本章中,它通过“apue.h”服务于“定义公共头”:先固定平台、编译宏、输入与初始资源表,再记录原始返回值和系统可见状态。
验证时只改变一个长度、容量、时序、权限、信号或失败点,并在进入“声明错误API”前停住第一条返回值、errno、系统调用轨迹、对象计数或状态分叉。最后关闭描述符、回收进程/线程、删除命名对象并恢复终端或信号掩码;同输入重放回到基线,结论才成立。
B.1 公共头文件 apue.h
“B.1 公共头文件 apue.h”不是孤立API名词。画出名字、描述符、打开对象、偏移、缓存与持久对象的关系,并标明复制、继承、刷新和最终释放时刻。在本章中,它通过“标准错误例程”服务于“声明错误API”:先固定平台、编译宏、输入与初始资源表,再记录原始返回值和系统可见状态。
验证时只改变一个长度、容量、时序、权限、信号或失败点,并在进入“格式化上下文”前停住第一条返回值、errno、系统调用轨迹、对象计数或状态分叉。最后关闭描述符、回收进程/线程、删除命名对象并恢复终端或信号掩码;同输入重放回到基线,结论才成立。
B.2 标准出错例程
“B.2 标准出错例程”不是孤立API名词。区分标准保证、实现选择与运行时查询结果,用功能测试宏和探测程序替代平台常量假设。在本章中,它通过“errno”服务于“格式化上下文”:先固定平台、编译宏、输入与初始资源表,再记录原始返回值和系统可见状态。
验证时只改变一个长度、容量、时序、权限、信号或失败点,并在进入“保留errno”前停住第一条返回值、errno、系统调用轨迹、对象计数或状态分叉。最后关闭描述符、回收进程/线程、删除命名对象并恢复终端或信号掩码;同输入重放回到基线,结论才成立。
分步视觉验证
先预测对象、返回值和状态,再动手试一试;若结果不同,停在第一条系统调用或对象状态分叉。
常见误区
四类样本与验收
| 样本 | 只改变什么 | 必查证据 | 通过条件 |
|---|---|---|---|
| 基线 | 平台、宏与固定输入 | 返回值、errno、对象与轨迹 | 与预测一致 |
| 边界 | 长度、容量、权限或时序 | 短计数、拒绝或阻塞点 | 边界可解释 |
| 故障 | 一个信号、断开或失败注入 | 首错与责任层 | 故障可定位 |
| 恢复 | 关闭、回收、删除与属性还原 | 残留对象和同输入重放 | 回到基线 |
练习
小结
- apue.h:连接“定义公共头”的接口合同与运行证据。
- 标准错误例程:连接“声明错误API”的接口合同与运行证据。
- errno:连接“格式化上下文”的接口合同与运行证据。
- 可变参数:连接“保留errno”的接口合同与运行证据。
- 构建底座:连接“链接示例”的接口合同与运行证据。
- 本页3个正式目录层级全部进入可重放实验链。