Dennis Ritchie(1993 年)撰写了an article about the history of C,以及它是如何从 B 逐渐演变而来的。一些设计决策的动机是避免对用 B 或 C 的雏形版本编写的现有代码进行源代码更改。
特别是,Lesk 写了一个“便携式
I/O 包' [Lesk 72] 是后来的
重做成为C`标准
I/O' 例程
C 预处理器直到 1972/3 才引入,所以 Lesk 的 I/O 包是在没有它的情况下编写的!(在非常早期的非 C 中,指针适合平台上的整数正在使用,将隐式int返回值分配给指针是完全正常的。)
在 1972-3 年左右发生了许多其他变化,但最重要的是引入了预处理器,部分原因是 Alan Snyder [Snyder 74] 的敦促
如果没有#include 和#define,则无法选择IO_READ | IO_WRITE 这样的表达式。
在 1972 年,fopen 在没有 CPP 的情况下调用的典型源代码中的选项是:
FILE *fp = fopen("file.txt", 1); // magic constant integer literals
FILE *fp = fopen("file.txt", 'r'); // character literals
FILE *fp = fopen("file.txt", "r"); // string literals
魔法整数文字显然很可怕,所以不幸的是,显然最有效的选项(Unix 后来为open(2) 采用)因缺少预处理器而被排除在外。
字符文字显然是不可扩展的;大概这对 API 设计者来说是显而易见的,即使在当时。但是对于fopen 的早期实现来说已经足够了(而且效率更高):它们只支持单字符串,检查*mode 是否为r、w 或a。 (见@Keith Thompson's answer。)显然r+ for read+write(不截断)后来出现了。 (有关现代版本,请参阅 fopen(3)。)
C 确实有一个字符数据类型(添加到 B 1971 作为生产胚胎 C 的第一步,所以它在 1972 年仍然是新的。原始 B 没有 char ,是为将多个字符打包成一个单词的机器编写的,所以char() 是一个索引字符串的函数!请参阅 Ritchie 的历史文章。)
使用单字节字符串实际上是通过 const 引用传递 char,由于库函数不能内联,因此会产生所有额外的内存访问开销。 (原始编译器可能没有内联任何东西,即使是在同一个编译单元中的琐碎函数(不像 fopen)也会缩小总代码大小以内联它们;现代风格的微型辅助函数依赖于现代编译器来内联它们。)
PS:Steve Jessop 的同样引用的回答启发了我写这篇文章。
可能相关:strcpy() return value。 strcpy 可能也写得很早。