C是什么样的语言

C是什么样的语言

做者: baiyuzhong

文/前桥和弥 html

在Donald C. Gause 和Gerald M. Weinberg 合著的《你的灯亮着吗?》一书中,有这样一节。 程序员

某计算机制造商开发了一种新型打印机。技术小组在如何保证打印精度的问题上很是苦恼,每次进行新的测试时,工程师都不得不花很长的时间测量打印机的输出结果来追求精确性。
丹(Dan Daring)是这个小组中最年轻但或许是最聪明的工程师。 他发明了一种工具,即每隔8 英寸就在铝条上嵌上小针。使用这个工具,能够很快地找到打印机输出位置的偏差。
这个发明显著地提升了生产效率,丹的上司很是高兴,提议给丹颁发一个公司的特别奖赏。他从车间里拿了这个工具,带回办公室,这样他写报告的时候还能够仔细地研究一下。
这个上司显然还用不惯这个工具,当他把这个工具放在桌子上 的时候,将针尖朝上了。更不幸的是,当丹的上司的上司友好地坐 到桌角上,打算谈谈给丹颁发奖励时,部门内的全部人都听到了他 痛苦的尖叫声——他的屁股上被扎了两个相距8 英寸的孔。 编程

C 语言就恰如这个工具。也就是说,它是一门 数组

  • 为了解决眼前问题,由开发现场的人发明的,
  • 虽然使用方便,
  • 但看上去不怎么顺眼,
  • 若是不熟悉的人糊里糊涂地使用了它,不免会带来“悲剧”的语言。

C 的发展历程 编程语言

众所周知,C 本来是为了开发UNIX 操做系统而设计的语言。 工具

如此说来,好像C 应该比UNIX 更早问世,惋惜事实并不是如此,最先的 UNIX 是用汇编来写的。由于厌倦了老是苦哈哈地使用汇编语言进行编程,UNIX 的开发者Ken Tompson 开发了一种称为“B”的语言。B 语言是1967 年剑桥大学的Martin Richard 开发的BCPL(Basic CPL)的精简版本。BCPL 的前身是1963 年剑桥大学和伦敦大学共同研究开发的CPL(Combined Programming Lanugage) 语言。 测试

B 语言不直接生成机器码,而是由编译器生成栈式机(Stack Machine)用 的中间代码,中间代码经过解释器(interpreter)执行(相似Java 和早期的 Pascal)。所以,B 语言的执行效率很是低,结果,在后来的UNIX 开发过程当中人们放弃了使用B 语言。 优化

在这以后的1971 年,Ken Tompson 的同事Dennis Ritchie 对B 语言作了改良,追加了char 数据类型,而且让B 语言能够直接生成PDP-11的机器代码。曾经在很短的时间内,你们将这门语言称为NB(New B)。 spa

以后,NB 改称为C 语言——这就是C 语言的诞生。后来,主要是为了知足使用UNIX 的程序员的须要,C 语言一边接受来自各方面的建议,一边摸着石头过河般地进行着周而复始的功能扩展。1978 年出版了被称为C 语言宝典的The C Programming Language 一书。此书取了两位做者(Brian Kernighan 和Dennis Ritchie)的姓氏首字母, 简称为K&R。在后面提到的ANSI 标准制定以前,此书一直做为C 语言语法 的参考书被人们普遍使用。据说这本书在最初发行的时候,Prentice-Hall 出版社制订了对于当时存在 的130 个UNIX站点平均每一个能卖9 本的销售计划(相比Lift With UNIX[2])。固然了,哪怕是第一版K&R的销售量,也以3 位数的数量级超过了 Prentice-Hall 出版社最初的销售计划 。本来只是像“丹的工具”同样为了知足 自用的C 语言,历经坎坷,最终成为全世界普遍使用的开发语言。 操作系统

顺便提一下,经过http://www.cs.bell-labs.com/cm/cs/cbook/index.html能够看到K&R 的网页,各语种的K&R 封面排列在一块儿,颇为壮观。

为何存在奇怪的指针运算

若是试图访问数组的内容,老老实实地使用下标就能够了。为何存在指针运算这样奇怪的功能呢?

其中的一个缘由就是受到了C的祖先B语言的影响。

B是一种“没有类型”的语言。B中可使用的类型只有word 型(也就是整型),指针也是做为整型来使用的(像浮点型这样高级的事物,你根本见不到)。B 是虚拟机上运行的解释器,这个虚拟机以word 为单位分配内存地址(现在普通的计算机以字节为单位)。因为B以word 为单位,若是指针(仅仅是表现地址的简单的整数)加1,指针就指向数组的下一个元素。为了继承这种特性,C引入了“指针加1,指针前进它所指向类型的长度”这个规则。B 语言中一样存在p[i]是 (p + i)的语法糖这样的规则。但是,这里的(p + i)只不过是单纯的整数之间的加法运算。解引用*、地址运算符&,也以几乎和C相同的形态存在于B语言中。另外还有一个理由就是,早先使用指针运算能够写出高效的程序。一般状况下,咱们老是使用循环语句来处理数组,通常都写成下面的形式,

for (i = 0; i < LOOP_MAX; i++) {
/*
* 在这里,使用array[i]进行各类各样的处理。
* array[i]会出现屡次。
*/
}

array[i]在循环中会出现屡次,每次都要进行至关于 array+i的加法运算,效率天然比较低。
所以,可使用指针运算重写上面这段循环,

for (p = &array[0]; p != &array[LOOP_MAX],p++) {
/*
* 在这里,使用*p进行各类各样的处理。
* *p会出现屡次。
*/
}

尽管*p在循环内部会出现屡次,但加法运算只有在循环结束的时候执行一次。

K&R p.119 中叙述了“通常状况下,使用指针的程序比较高效”。上面的说明应该能够做为这段叙述的根据吧。但是,这些不管怎样都是老黄历了。

现在,编译器在不断地被优化,对于循环内部重复出现的表达式的集中处理,是编译器优化的基本内容。对于如今通常的C 编译器,不管你使用数组仍是指针,效率上都不会出现明显的差距。基本上都是输出彻底相同的机器码。

总的来讲,C 的指针运算功能的出现,源自于早期的C自身没有优化手段。这一点并不奇怪,请你们回想一下在前面介绍过的内容,C原本只是为了解决开发现场的人们眼前的问题而出现的一种语言。Unix 以前的OS几乎都是使用汇编写的,即便晦涩难懂,人们也不会大惊小怪。对于当时的环境,追求什么编译器优化实在有点勉为其难。所以,当初开发C 语言的时候,是彻底有必要提供指针运算功能的。但是……

不要滥用指针运算

被称为C语言宝典的K&R 指出:“通常状况下,使用指针的程序比较高效。”这彻底是“那个时代的错误”。

但是,正如前面所说,对于现在的编译器,不管是使用指针运算仍是下标运算,都生成几乎彻底相同的执行代码。

事到现在……难道不该该放弃使用指针运算,老老实实地使用下标访问吗?

虽然K&R 被不少人奉为“神书”,但是对于我来讲,它连做为菜鸟实习的资料也未入流。为何这么说?由于在此书中,那些滥用指针的例程彻底可让你崩溃。

莫名其妙地使用像*++args[0]这样的语句,而且乐此不疲,实在让人心烦。

K&R 里面记载了下面这个做为strcpy()实现的例子:

/* 将t拷贝成s;指针版3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

虽然乍一看不容易理解,可是这种写法实际上是很是方便的。由于会在C 程序中常常遇到,因此咱们应该掌握这种惯用写法。既然知道“乍一看不容易理解”,那就不该该这样写,难道不是吗?

满大街的C 语言入门书都在教育咱们,使用指针运算比使用下标会让程序

☑更有效率
☑更有C 语言范儿

所谓的“更有效率”,只不过是臆想罢了。对于这种“微不足道的”优化工做,与其让人去当心翼翼地作,还不如交给编译器来干。

所谓“更有C语言范儿”好像是有些道理。若是只是为了要让程序“有范儿”,而让代码变得晦涩难懂,那么仍是拜托你行行好,扔掉这种恶习吧。

在学校里,咱们要完成一些课后做业。好不容易完成了一个使用下标的程序题,不料后面的那道题为“请使用指针将刚才那道题的程序从新完成一遍”。这种事常有吧。

老实说,这种事很无聊。也许你会很“威武”地依然使用下标原封不动
地把程序又写了一遍,而后交给了老师。面对老师的指责,你义正辞严:

咦,下标运算符[]只不过是指针运算的语法糖而已,在本质上这样的写法也是在使用指针啊。

尽管这样,这位可爱的老师可能仍是不会放过你,因而你就急了:

行,不就是把像p[i]这样使用下标的地方,机械地一个个替换成* (p+i)嘛。

话说回来,丢了学分,我可不负责哟。在C的世界里,使用指针运算要比使用下标的写法让人感受更“帅一些”。

可是……与其在这些无聊的地方“耍酷”,倒不如多花点时间学一些有用的知识。你要知道,做为一个程序员,还有堆积如山的知识等着你去掌握呢。

固然,什么样的规则都有例外,好比,在“一个巨大的char 数组中,参杂了各类类型的数据①,而且咱们试图读取第多少字节的数据”这样的状况下,仍是使用指针运算写的程序比较容易理解。

此外,做为一个C程序员连指针运算的代码也读不懂,多少有点可悲。

尽管如此,让咱们至少从如今开始尽可能使用下标来写新的程序,这样作对本身,以及对之后有机会阅读你的程序的人,都有好处。

做者前桥和弥(Maebasi Kazuya),1969年出生,著有《完全掌握C语言》、《Java之谜和陷阱》、《本身设计编程语言》等。其一针见血的“毒舌”文风和对编程语言深入的见地受到广大读者的欢迎。

本文选自《征服C指针》一书,做者前桥和弥,吴雅明译,由人民邮电出版社出版。

相关文章
相关标签/搜索