标准I/O库和C预处理器
C编译器不曾实现的一些功能必须通过其他途径实现。在C语言中,它们在运行时进行处理,既可以出现在应用程序代码中,也可以出现在运行时函数库中(runtime library)。在C语言中,绝大多数库函数或辅助程序都需要显式调用。例如, C语言(必要时),程序员必须管理动态内存的使用,创建各种大小的数组,测试数组边界,进行范围检测。
C原先并没有定义I/O,而是由库函数提供。后来,这实际上成了标准机制。
可移植的I/O由Mike Lesk编写,最初出现在1972年,经过优化和裁剪后来成为标准I/O函数库。
C预处理器
倡仪者:Alan Snyder
时间:1972
实现的3个主要功能:
字符串替换。通常用于为常量提供一个符号名。
头文件包含。(一般性的声明被分离到头文件中,并且可以被许多源文件使用,虽然约定采用以.h作为头文件的扩展名)
通用代码模板的扩展。与函数不同,宏(marco)在连续几个调用中所接收的参数的类型可以不同(宏的实际参数只是按照原样输出)在宏的扩展中,空格会对扩展造成很大的影响。
//1.
#define a(y) a_expanded(y)
a(x);
被扩展为
a_expanded(x);
#define a (y) a_expanded(y)
a(x);
被扩展为
(y) a_expanded(y)(x);
你可能会以为在宏里面使用花括号就像在C语言的其他部分一样,能把多余语句组合成一条复合语句,但实际上并非如此。对于宏这样的预处理器,只应该适量使用。
//2.
/*人物:Steve Bourne
*地点:贝尔实验室
*UNIX第7版的Shell(命令解释器)
*使用预处理器使C语言看上去更像Algol-68
*/
#define STRING char *
#define IF if (
#define THEN ) {
#define ELSE } else (
#define FI ;}
#define WHILE while (
#define DO ) {
#define OD ;}
#define INT int
#define BEGIN {
#define END }
INT compare(s1, s2) STRING s1; STRING s2;
BEGIN
WHILE *s1++ == *s2
DO IF *s2++ == 0
THEN return(0)
FI
OD
return (*--s1 - *s2);
END
/*翻译,原模原样替换就行*/
int compare(s1, s2) char *s1; char *s2;
{
while (*s1++ == *s2 ) {
if (*s2++ == 0) {
return (0);
}
;}
return (*--s1 - *s2);
}
相应的C代码:
int compare(s1, s2)
char *s1, *s2;
{
while (*s1++ == *s2) {
if (*s2++ == 0) return (0);
}
return (*--s1 - *s2);
}
/*Shell不使用malloc,而是使用sbrk自行负责堆存储的管理,Steve解释说,
*他之所以采用这种特别的内存分配器,是为了提高字符串处理的效率
*/
/*Bource创立的这种C语言变体事实上促成了异想天开的国际C语言混乱代码大赛
*(The International Obfuscated C Code Competition)
*/
宏最好只用于命名常量,并未一些适当的结构提供简捷的记法。宏名应该大写,这样便很容易
与函数调用区分开来。千万不要使用C预处理器来修改语言的基础结构,因为这样一来C语言就不是C语言了。