第1章 C:穿越时空的迷雾
1. C语言史前阶段
B 语言通过省略一些特性(如过程嵌套和一些循环结构),对BCPL语言做了 简化,并发扬了"引用数组元素相当于对指针加偏移量的引用"这个想法。B语言同时保持了BCPL语言无类型这个特点,它仅有的操作数就是机器字。 Thomposoon发明了++和--操作符,并把它加入到PDP-7的B编译器中。
2. C语言的早期体验
除了类型系统之外,C语言的许多其他特性是为了方便编译器设计者而建立的。主要包括
(1)数组下标从0而不是从1开始。因为偏移量的概念在编译器设计者的心中已经是根深蒂固。
(2)C语言的基本数据类型直接与底层硬件相对应.例如,不像Fortran,C中不存在内置的复数类型。某种语言要素如果底层硬件没有提供直接的支持,那么编译器设计者就不会在它上面浪费任何精力。C语言一开始并不支持浮点类型,直到硬件系统能够直接支持浮点数之后才增加了对它的支持。
(3)auto关键字显然是摆设。这个关键字只对创建符号表入口的编译器设计者有意义。
(4)表达式中的数组名可以看作是指针。把数组当作指针,简化了很多东西。不再需要一种复杂的机制区分他们,把它们传递到一个函数时不必忍受必须复制所有数组内容的低效率。
(5)float被自动扩展为double。尽 管在ANSI C中的情况不再如此,但最初浮点常量的精度都是double型的,所有表达式中float变量总被自动转换成double。这样做的理由主要与PDP- 11中浮点数的硬件表示方式有关。首先,在PDP-11或VAX中,从float转换到double的代价非常小,只要在后面 增加一个每个位均为0的字即可。如果要转换过去,去掉第二个字就可以了。其次,要知道在某些PDP-11的浮点数硬件表示中有一个运算模式位(mode bit),你可以只进行float的运算,也可以只进行double的运算,但是如果要想在这两种方式之间进行切换,就必须修改这个位来改变运算模式。在 早期 的UNIX程序中,float用的不是很多,所以把运算模式固定为double是比较方便的,省的编译器设计者去跟踪它的变化。
(6)不允许嵌套函数。这简化了编译器,并稍微提高了C程序的运行时组织结构。
(7)register关键字。这个设计是一个失误。如果让编译器在使用各个变量时自动处理寄存器的分配工作,显然比一经声明就把这个类变量在声明期内始终保留在寄存器里要好。使用register关键字,简化了编译器,却把包袱丢给了程序员。
和其他语言不同,C语言有一个漫长的进化过程。在 目前的形式之前,它经历了很多中间状态。它经历多年,从一个实用工具进化为一种经过大量试验和测试的语言。第一个C编译器大约出现在1970。时光荏苒, 作为它的根基的UNIX系统得到了广泛使用,C语言也随之茁壮成长。它对直接由硬件支持的底层操作的强调,带来了极高的效率和移植性,反过来也帮助 UNIX获得了巨大的成功。
第3章 分析C语言中的声明
char *const*(*next)();
next是一个指针,它指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针。
第5章 对链接的思考
第6章 运行时结构
第7章 对内存的思考
第8章 为什么程序员无法分清万圣节与圣诞节
第9章 再论数组
为什么C语言把数组形参当成指针
多维数组
第11章 你会C员,那么C++不在话下
面向对象编程
抽象
构造函数
虚函数与多态
C++设计目标
C++与C之间的关系
附录A
库函数与系统调用
文件描述符与文件指针