Dennis Ritchie说,C诡异离奇,缺陷重重,却获得了巨大成功。
关于历史
1969,通用电气,MIT,贝尔实验室——Multics工程(目的创建一个操作系统)失败了。他们试图建立一个非常巨大的操作系统
能够应用与规模很小的硬件系统中。Multics成了总结工程教训的宝库,同时为C语言体现“小即是美”铺平了道路
Ken Tompson,为PDP-7编写了一个建议的新型操作系统,取名为Unix。(使用PDP-7汇编语言编写,汇编语言笨拙,难以调试,理解困难)
Tompson想使用高级语言,尝试Fortran失败,然后他将BCPL语言做了简化创造了B语言。B语言从来不曾真正成功,因为硬件系统的内存限制,
它只允许放置解释器,而不是编译器,由此产生的低效阻碍了使用B语言进行Unix自身的系统编程。
B语言是无类型语言,它仅有的操作数就是机器的字。Tompson发明了++和--操作符。开发平台转移到PDP-11时,无类型语言很快就不合时宜了,效率很成问题。
Dennis Ritchie创立了能够同时解决多种数据类型和效率的"New B"语言,该名称很快变成了C语言。采用编译模式,引入了类型系统。
——编译器设计者的金科玉律:效率(几乎)就是一切。编译器的效率包括两个方面:运行效率(代码运行效率)和编译效率(产生可执行代码的速度)。
注意:早期的C语言中float类型会自动扩展为double,现在不再如此。
C语言是为了C编译器设计者的方便而建立起来的,这大大简化了C语言本身,通过回避一些复杂的语言要素,C语言更容易学习和实现,效率非常高。
C语言随着Unix而茁壮成长,反之也帮助Unix获得了巨大成功。
1972年左右,C预处理器加入。注意:对于宏这样的预处理器,只应该适量使用。
70年代后期,Steve Bourne使用C预处理器编写了shell,即Bourne Shell。促成了异想天开的国际C语言混乱代码大赛。
sbrk程序是什么?————这个小问题!!
indent程序,代码格式修改器。任何格式器都不应该修改程序中除空白之外的任何东西。
1978年Brian Kernighan和Dennis Ritchie编写了《The C Programming language》,这个版本的C语言被称为“K&R C”
ANSI C,
C语言的标准化,1989年12月C语言标准被ANSI委员会采纳,俗称C89
1990年初,ANSI重新采纳了ISO C,取代了原来的版本,它的官方名称为“ISO/IEC 9899:1990”
关于ANSI C中的术语
不可移植代码
由编译器定义的implementation-defined——不同编译器的处理结果可能不同,但这是正确的。
未确定的unspecified——在某些正确情况下的做法,标准未明确规定
坏代码
未定义的undefined——在某些不正确情况下的做法,标准未规定该怎样做。
约束条件a constraint——必须遵守的限制或要求。标准规定,编译器只有在违反语法规则和约束条件的情况下才产生错误信息。
可移植代码
严格遵循标准的strictly-conforming——只使用已确定的特性,不突破任何右边一起实现的限制,
不产生任何依赖由编译器定义的或未确定的或未定义的特性的输出。——这样可以最大限度地保证移植性
遵循标准的conforming——可以一览一些某种编译器特有的不可移植的特性
编译限制,这些“必须”的限制实际上不是a constraint,编译器违反时不一定产生错误信息。
每个ANSI C编译器必须能够支持:
1 函数定义形参数量的上限至少为31个
2 函数调用实参数量的上限至少为31个
3 一条源代码里至少可以有509个字符
4 在表达式中至少可以支持32层嵌套的括号
5 long型整数不得低于32位
原型的目的是对函数作前向声明,编译器能在编译时对函数调用中的实参和函数声明中的实参,进行一致性检查。
K&R C中,该检查被推迟到链接时,或者干脆不做检查。例如:
K&R C原型: char *strcpy();
K&R C实现: char *strcpy(dst, src)char *dst, *src;{}
ANSI C原型:char *strcpy(char *dst, char *src);
ANSI C实现:char *strcpy(char *dst, char *src){}
ANSI C标准有这样的话:
简单赋值必须满足,下列两种条件之一
两个操作数都是指向有限定符或无限定符的向荣类型的指针,
左边指针所指向的类型必须具有右边指针所指向类型的全部限定符。
对于const char * 与 char *,下面赋值是合法的
char *cp;
const char *ccp;//ccp为指向一个具有const限定符的char类型的指针
ccp = cp;
char ** 与 const char ** 不相容,不能直接赋值。
const不能把变量变成常量,例如:
/*改变const变量的值*/
void change_const()
{
const int a = -1;
int *b = &a;
*b = 2222;
printf("%d/n",a);
}
//结果:2222
有关于const的用法,以后在C/C++中总结
/*使用无符号数的BUG*/
void use_unsign()
{
int d = -1, x;
int arr[]={1,2,3,4,5,6,7};
#define T (sizeof(arr)/sizeof(arr[0]))//sizeof()返回的size_t是无符号整数
if(d <= T-2)//有符号数与无符号数比较,有符号数提升为无符号数,d是超大正数
{
x = arr[d+1];
printf("%x/n",x);
}
else
{
printf("Direct End/n");
}
} //结果:Direct End
编程启发:尽量不要在代码中使用无符号类型,以免增加不必要的复杂性。
在《C专家编程》一书中,有许多趣味洋溢的妙文,可顺手拿来,启发心智,博取一笑。
在K&R C的许多特性中,有许多在ANSI C中进行了更改,包括许多所谓的“安静的变化”,这种情况下,代码在两种编译器中都能运行,但具体含义稍有差别。程序员越到这种情况时,其反应可想而知,因此这种转变可称为“讨厌的转变”。
我们所说的“黑客”,他的原意是“天才程序员”,后来,这个称呼被媒体所贬损,致使他在局外人眼中成了“邪恶的天才”的代名词。