附录 — 创建库、Unicode 与 UTF-8、日期格式符¶
这一章讲什么: 三个附录打包:附录 A 教你亲手造库(第 3 章 起一直在用
libspl.a,这里是它的出生证明);附录 B 把 Unicode 和 UTF-8 一次讲透——为什么全世界的文字能在 Linux 文件里共存;附录 C 是strftime格式符的速查表。
1. 附录 A:创建库¶
静态库:ar rcs 六步¶
- 写头文件(放原型);2.
gcc -c编译出.o;3.ar rcs libutils.a timestuff.o errors.o——r=插入、 c=无存档则建、s=建索引;4. 装到~/lib、头文件到~/include(最贴近的祖先把原则);5.LIBRARY_PATH加库目录;6.CPATH加头文件目录。使用:gcc -o myprog myprog.c -lutils(-l 要跟在引用它的文件 后面)1。
三个坑,原书都给了警示框:① 静态库和共享库别放同一目录
——gcc 默认优先链共享库,同名时你的静态库会被无声忽略;
② cannot find -lutils = LIBRARY_PATH 没配对(export 了吗?);
③ 别用 gcc -static——它要求所有库(包括 libc)都有
静态版,而现代系统根本不带 libc.a2。
共享库:三重名字 + 六步¶
共享库有三个名字,libacl 的真实目录布局就是教科书:
libacl.so → 软链 → libacl.so.1 ← linker name(编译器用)
libacl.so.1 → 软链 → libacl.so.1.1.0 ← soname(接口版本号)
libacl.so.1.1.0 真实文件 ← real name(带 minor.release)
主版本号变 = 接口变了;修 bug 只动 minor/release3。建造六步:
① gcc -fPIC -c(位置无关代码——别用 -fpic,不保证通用)
② gcc -shared -Wl,-soname,libgoodstuff.so.1 -o libgoodstuff.so.1.0.1 stuff.o tools.o(-Wl 把选项透传给链接器,逗号两侧不留空白)
③ 拷到 ~/lib;④ ldconfig -n ~/lib 自动建 soname→real 的
软链;⑤ 手动 ln -s 建 linker name;⑥ 升级时放新 release
再跑 ldconfig,软链自动指到最新4。
用共享库:两步链接 + 运行时找库¶
链接期照常 -L~/lib -lgoodstuff;运行期动态链接器要能找到
文件——ldd myprog 验货,看到 libgoodstuff.so.1 => not found
就是找不到。三条路:LD_LIBRARY_PATH=~/lib(bashrc 配置,
最省事但不被推荐)、-rpath 编译期烧进路径、
LD_RUN_PATH=~/lib(ld 的等价物)5。
2. 附录 B:Unicode 与 UTF-8¶
码位 ≠ 字节¶
历史线:ASCII(7 位,94 可打印 + 33 控制 + 空格)→ IBM 的 EBCDIC(另一套 8 位映射)→ 各家民族编码互相撞车。1989 年 ISO 启动 UCS(ISO 10646),1991 年与 Unicode 联盟合并推进—— 码位(code point)只是分配给字符的数值(U+03C6 是「ϕ」的 号,不是两个字节),码位→字节序列的映射才叫编码 (encoding form),再加分端序(字节序)才是完整的编码方案 (encoding scheme)6。
UCS-2/UCS-4 直接按数值写字节,会产出含 \0 和 / 的序列——
Unix 文件系统和 C 库全都完蛋。UTF-8(Ken Thompson 1992 年
发明)救场:变长 1–6 字节,规则四条7:
- U+0000–U+007F = 单字节 0x00–0x7F——纯 ASCII 文件就是 合法的 UTF-8 文件,这是它统治 Unix 的原因;
- 非 ASCII 字符 = 首字节 0xC0–0xFD(几个 1 跟几个后续字节: 110xxxxx 表 1 个跟随,1110xxxx 表 2 个)+ 跟随字节一律 10xxxxxx(0x80–0xBF);
- 编码模板表:
0xxxxxxx/110xxxxx 10xxxxxx/1110xxxx 10xxxxxx 10xxxxxx/ ……(1 到 6 字节); - 0xFE/0xFF 永不出现——自同步 + 不含
/。
手算一例:U+05E7(0080–07FF 区间 → 2 字节)二进制
0000 0101 1110 0111:右 6 位 100111 填第二字节(前缀 10)
→ 10 100111;余 5 位 10111 填首字节(前缀 110)→
110 10111——两字节序列 11010111 10100111(0xD7 0xA7)8。
码位到字节数的区间表(Unicode 16):1 字节 ≤7F;2 字节 ≤07FF;
3 字节 ≤FFFF(BMP 全部);4 字节到 1FFFFF(实际只到 10FFFF,
UTF-8 最多 4 字节)9。
3. 附录 C:日期时间格式符速查¶
strftime/strptime 的 % 格式符全表,示例基准取
2038-01-19 03:14:07 UTC(刻意选 32 位 time_t 溢出瞬间,
附录 C 的冷幽默)。常考的十个:%a 缩写星期(Mon)、%A 全名、
%b/%B 月名、%c locale 日期时间、%d 月内日、%D =
%m/%d/%y、%F = %Y-%m-%d、%H 24 小时、%I 12 小时、
%j 年积日、%m 月、%M 分、%S 秒、%Y 四位年、%Z
时区名、%% 百分号。完整表见原书附录 C,locale 改变时
%a/%A/%b/%B/%c 的输出随之变(第 3 章 spl_date 的实验基座)10。
4. 判断与边界¶
判断: 「别用 -fpic/-static」两条禁令都是踩坑经验的凝结; UTF-8 的「ASCII 兼容」作为它胜出的主因,论据硬47。 边界: soname 机制在 macOS 上是 install_name、Windows 是 DLL 名字规则——跨平台要重查;UTF-8 的四字节上限与实际 码位空间 10FFFF 的对应、以及 surrogate 代理对的 UTF-16 细节,附录点到为止;附录 C 只管 strftime 家族,date(1) 的 GNU 扩展格式另有一套。可带走的: ar rcs 六步;静态/共享 分目录;三重命名 + ldconfig;LD_LIBRARY_PATH/ldd 排障; 码位≠字节;UTF-8 四条规则 + 区间表 + 手算流程;十大格式符。
5. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 静态库六步与 LIBRARY_PATH | Appendix A: Creating Libraries | text/26-apx-a-appendix-a-creating-libraries.txt:132(搜「ar rcs」) · :175(搜「LIBRARY_PATH」) |
| 同名共享库优先的坑 | 同上 | :220(搜「shared library of the same name」) |
| -static 陷阱 | 同上 | :246(搜「cannot find -lc」) |
| 三重命名 | 同上 | :262(搜「soname」) · :287(搜「libacl.so」) |
| 共享库六步 | 同上 | :302(搜「-fPIC」) · :319(搜「-Wl,-soname」) · :338(搜「ldconfig」) |
| ldd/LD_LIBRARY_PATH | 同上 | :403(搜「ldd」) · :425(搜「LD_LIBRARY_PATH」) |
| 码位与编码形式 | Appendix B: Unicode and UTF-8 | text/27-apx-b-appendix-b-unicode-and-utf-8.txt:100(搜「numeric values」) · :111(搜「UCS-2」) |
| UTF-8 四规则 | 同上 | :126(搜「scheme」) · :137(搜「110xxxxx」) · :155(搜「0xFE」) |
| 区间表与手算 | 同上 | :168(搜「Table B-1」) · :193(搜「U+05E7」) |
| 格式符示例基准 | Appendix C: Date and Time Format Specifiers | text/28-apx-c-appendix-c-date-and-time-format-specifiers.txt:5(搜「2038」) |
-
出处:「Appendix A: Creating Libraries」第 118–193 段(
text/26-apx-a-appendix-a-creating-libraries.txt:132,搜「ar rcs」) · :175(搜「LIBRARY_PATH」)。 ↩ -
出处:「Appendix A: Creating Libraries」第 192–253 段(
text/26-apx-a-appendix-a-creating-libraries.txt:220,搜「shared library of the same name」) · :246(搜「cannot find -lc」)。 ↩ -
出处:「Appendix A: Creating Libraries」第 261–295 段(
text/26-apx-a-appendix-a-creating-libraries.txt:262,搜「soname」) · :287(搜「libacl.so」)。 ↩ -
出处:「Appendix A: Creating Libraries」第 297–375 段(
text/26-apx-a-appendix-a-creating-libraries.txt:302,搜「-fPIC」) · :319(搜「-Wl,-soname」) · :338(搜「ldconfig」)。 ↩↩ -
出处:「Appendix A: Creating Libraries」第 376–446 段(
text/26-apx-a-appendix-a-creating-libraries.txt:403,搜「ldd」) · :425(搜「LD_LIBRARY_PATH」)。 ↩ -
出处:「Appendix B: Unicode and UTF-8」第 100–120 段(
text/27-apx-b-appendix-b-unicode-and-utf-8.txt:100,搜「numeric values」) · :111(搜「UCS-2」)。 ↩ -
出处:「Appendix B: Unicode and UTF-8」第 121–155 段(
text/27-apx-b-appendix-b-unicode-and-utf-8.txt:126,搜「scheme」) · :155(搜「0xFE」)。 ↩↩ -
出处:「Appendix B: Unicode and UTF-8」第 181–209 段(
text/27-apx-b-appendix-b-unicode-and-utf-8.txt:193,搜「U+05E7」)。 ↩ -
出处:「Appendix B: Unicode and UTF-8」第 156–180 段(
text/27-apx-b-appendix-b-unicode-and-utf-8.txt:168,搜「Table B-1」)。 ↩ -
出处:「Appendix C: Date and Time Format Specifiers」第 1–40 段(
text/28-apx-c-appendix-c-date-and-time-format-specifiers.txt:5,搜「2038」)。 ↩