解读《C标准库》
《C 标准库》将告诉你如何使用符合 C 语言的 ANSI/ISO 标准的库函数 。 因为已经有很多书出色地讲解了 C 语言本身 , 所以本书只专注于 “ 库 ” 这个话题 。 本书还会告诉你 C 标准库是如何实现的 。 本书提供了大约 9 000 行测试过的可实际工作的代码 。 我相信 , 看了 C 标准库的实现细节后你能更好地理解如何使用它 。
本书相关链接: http://www.cnblogs.com/turingbooks/archive/2009/06/05/1496990.html
库函数的实现代码尽可能地使用标准 C , 这样做有 3 个设计目的 : 首先 , 它使代码具有可读性和示范性 ; 其次 , 它使代码在各种计算机体系结构间具有高度可移植性 ; 最后 , 它能使编写的代码兼顾正确性 、 性能和规模各方面 。
教你如何编写 C 程序并不是本书的目的。本书假定你能读懂简单的 C 程序,对于那些稍有难度的代码,我会向你解释其中的难点和技巧。
C 标准库
C 标准库是非常强大的,它在多种不同的环境下提供了相当多的功能:它允许用户和实现者使用明确定义的名字空间;它对其所提供的数学函数的健壮性和精确性有非常严格的要求;它率先对适应不同文化习惯的代码提供支持,包括那些拥有很大字符集的文化习惯。
为了能有效利用标准库所提供的强大功能,用户应该了解其实现上的很多隐晦细节。库的实现者必须向用户提供这些细节,以使他们更好地使用标准库。C 标准中并没有把这些隐晦的实现细节都很好地描述清楚 , 因为制定标准的主要目的并不是给库的实现者提供指导 。 与 ANSI C 标准一起发布的 Rationale 也没有对这些细节作出很好的解释。Rationale 要服务的对象范围很广,而关注这些细节的标准实现者只是众多服务对象的一部分。
在 C 的传统实现中并不能找到上面提到的新特性 。 现在的实现已经可以支持国际化开发中的 区域设置 (locale)概念。每个区域设置都对应于专属的某个国家 、 某种语言或者某个职业的特定习惯,一个 C 程序可以通过修改和查询区域设置来动态地适应多种文化。现在的实现也能支持很大的字符集,如字符数量众多的汉字。C 程序能把它们作为 多字节字符(multibyte character )或者 宽字节字符(wide character)处理。它也能在这两种形式之间转换。在迅速加剧的市场竞争中,这就使得程序的编写更加简单和标准。
因为以前对这些新特性几乎不存在相应的编程艺术 ,所以即使是最有经验的 C 程序员 , 在使用区域设置 、 多字节字符和宽字节字符的时候也需要一些指导 。所以 ,这些主题在这里给予了特殊的关注 。
细节
本书向用户和实现者解释了库的设计用意和可能用法 。 通过提供 C 标准库中所有库函数的实际实现 , 本书用例子告诉你怎样处理它的细节 。 在那些没有明确是最好实现方法的地方 , 它还讨论了可供选择和折中的办法 。
一个涉及细节的例子是函数 getchar。头文件<stdio.h> 原则上可以用下面的宏来屏蔽函数的声明 :
#de f ine getchar() fgetc(stdin) /* NOT WISE! */
然而 , 它却不应该这样做 , 一个合理 ( 即使没有用 ) 的 C 程序是
#include <stdio.h>#undef fgetc
int main(void) { int fgetc = getchar(); /* PRODUCES A MYSTERIOUS ERROR */
return (0);
}
当然 ,这个例子有点极端,但它却阐述了即使是一个很好的程序员也可能犯的错误。用户有权要求尽可能少地出现这类奇怪的错误,所以设计者就有义务避免出现这些奇怪的错误。
我最终确定的 getchar 宏的形式是
#de f ine getchar () (_ Fi les[0]->_Next < _ Fi les[0]->_Rend \ ? *_ Fi les[0]->_Next++ : (getchar) ())
它和上面第一次给出的那个显而易见(而且更具可读性)的形式大不相同。第12 章会解释其中的原因 。
库的设计
本书还有一个目的 , 那就是从一般角度教授程序员怎样设计和实现库 。 从本质上讲 , 程序设计语言提供的库是一个混合的 “ 袋子 ” 。 库的实现者要具备非常广泛的技巧才能处理这个 “ 袋子 ” 中各种各样的内容 。 仅仅是一个有能力的数值分析员 , 或者能熟练高效地操作字符串 , 或者懂得很多操作系统接口方面的知识 , 都是不够的 。 编写库不仅需要具备以上所有能力 , 还需要掌握更多的知识 。
已经有很多好书告诉你怎样编写数学函数 , 也有很多书专门介绍某种特定用途的库 。 这些都是告诉你怎样使用现有的库 。 有些书甚至证明某个库的各种设计方案抉择的正确性 。 很少有书致力于告诉读者全面地构建一个库要求具备的技能 。
可复用性
很多书都介绍了设计和实现软件的一般性原则 。 这些书中提到的方法有结构化分析 、 结构化设计 、 面向对象设计和结构化编程等 。 这些书中的大部分例子只考虑了为某个应用编写的程序 。 然而 , 这些原则和方法也同样适用于可复用的库的实现 。但可复用性的目标进一步提高了要求 。 从结构化设计的角度来看 , 如果一个库函数没有很高的内聚性 , 它就不太可能有新的用途 。 同样 , 如果它不具备低耦合性 , 它就会更难使用 。 简单地说 , 库函数一定要隐藏它的实现细节并且提供完整的功能 。 否则 , 从面向对象的角度看 , 它们不能实现可复用的数据抽象 。
所以本书的最终目的是讨论构建库所特有的设计和实现问题 。 C 标准库的设计是固定的 。 然而 , 它从很多方面来看都是一个好的设计 , 值得讨论 。 C 标准库的实现也可以有很多选择 。 任何一个选择都要遵守一定的原则 , 例如正确性和可维护性等 。 其他的一些选择还要遵循某个项目特定的优先级 , 例如高性能 、 可移植性或者小规模等 。 这些选择和原则也值得讨论 。
本书的结构
本书的结构基本对应 C 标准库本身 。 标准库中 15 个头文件声明或定义了库中所有的名字 。 本书中每一章讲述一个头文件 。 大部分头文件都有比较紧凑的内容 , 书中对此也作了紧凑的讨论 。 然而 , 也有一两个很笼统 , 它们相应的章节自然也会涉及更多的内容 。
在本书的每一章中 , 我都摘录了 ISO C 标准的相关部分 。( 除了格式细节 , ISO 和 ANSI 的 C 标准是完全相同的 。) 这些摘录补充说明了库的每一部分通常是怎样使用的 。 它们也使本书成为一个更完整的参考手册 ( 当然本书比单独阅读 C 标准要容易理解 )。 本书也给出了实现那些部分和测试这些实现所需的代码 。
每一章最后都附有参考文献和配套习题 。 假如本书作为大学的教材使用 , 这些习题可以当成作业 。 很多习题都只是简单的代码改写 , 它们可以把某个知识点讲得更清楚或者能够说明在实现上可以做一些合理的修改 。 那些更具有挑战性的题目都做了标记 , 可以将它们作为那些长期项目的基础 , 而自学者则可以把这些习题当作深入思考的入口点 。
代码
本书中出现的代码已经在 Borland 、 GNU 项目和 VAX ULTRIX 的 C 编译器上进行了测试 。 它通过了广泛使用的 Plum Hall Validation Suite 的库函数的测试 , 也通过了那些专门为 C 实现设计的 、 发现 C 实现的缺陷的公共域程序 。 虽然我尽最大努力使错误减到最少 , 但仍然不能保证代码完全正确 。
同时也请注意本书的代码是受版权保护的 。 它没有放置在公共域中 , 也不是共享软件 。 和那些自由软件基金会 ( GNU 项目 ) 发布的代码不同 , 它不受 “ copyleft ” 协议的保护 。 我保留本书所有的权利 。
合理使用
你可以把书中的代码转变为电子版的形式 , 供个人使用 。 你也可以从堪萨斯州劳伦斯市的 C 用户组那里购买机器可识别的代码 。 无论哪种情况 , 你对代码的使用都要遵守版权法关于 “ 合理使用 ” 的规定 。 合理使用不允许你以任何形式发布这些代码的副本 , 不论是打印件还是电子版 , 也不论是免费的还是收费的 。
除了以上谈到的 , 我允许合理使用范围之外的一种重要用途 。 你可以编译库中的部分并且把生成的二进制目标模块和你自己的代码连接生成可执行文件 。 无限发布这样的可执行文件是允许的 。 对这样的副本我不要求任何权利 。 但是 , 我强烈要求你声明库 ( 在你的文件中 ) 的存在 , 不论你用了多少 , 也不论是修改过的还是没有修改的 。 请在可执行文件的某个地方把下面的文字包含进去 : “ 本作品的部分代码源自 The Standard C Library , copyright (c) 1992 by P. J. Plauger, Prentice-Hall 出版社出版 , 这些代码已获授权使用 。 ” 随可执行文件一同发布的文档中也要在适当的地方显著地标注这些内容 。 如果你遗漏了其中的任何内容 , 将被视为侵权 。
许可
你也可以被授权做更多的事 。 你可以以二进制目标模块的形式发布整个库 , 甚至可以发布本书中的源文件的副本 , 不论是否修改过 。 简单地说 , 你可以把整个库合并到一个让人们使用它来编写可执行程序的产品中 。 但是 , 所有的这些都需要许可证 。 你可以购买许可证 。 如果你想购买许可证而且想不断地获得库的支持 , 请和夏威夷州卡姆艾拉市的 Plum Hall 公司联系 。
虽然上面的几段有很浓的商业色彩 , 但我的主要目的不是推销一个商业产品 。 我非常信任 C 标准 , 也已经很努力地参与了它的制定 。 我花了很大的精力制定 C 标准库规范 。 我想证明我们创建了一个良好的语言标准 。 编写这个实现和这本书就是为了说明这个简单但很重要的事实 。
P. J. Plauger
邦迪 , 新南威尔士