8e7b775eecb1e6b31e47d59bd41730cd.gif

摘要:C 语言在编程世界中的重要性不言而喻。在操作系统开发、容器开发和嵌入式开发等领域,C 语言都具有大量的应用场景,因此即便诞生了几十年,C 语言依然是 IT 行业内最为流行的编程语言之一,C 语言程序员的发展前景也较为乐观。但同时,对于 C 语言程序员而言,也有一些需要重视的建议与告诫。

原文链接:https://doc.cat-v.org/henry_spencer/ten-commandments

声明:本文为 CSDN 翻译,未经授权,禁止转载。

作者 | Henry Spencer

译者 | 弯月

出品 | CSDN(ID:CSDNnews)

1. 应经常运行lint,并研习其教诲,因为它的直觉和判断通常比你强得多。

这一条说得很有道理,然而许多现代编译器也会找出许多同样的错误,lint本身也由于过时、判断标准不一致或者无法检测未知的领域而导致许多错误。还有许多像Saber C之类的其他工具也很有用。

“经常”的意思是你应该每天聆听其教诲,而不是在最后时刻期待着lint为代码降下福音。对从来没有lint过的程序进行lint,其结果通常会造成程序的不稳定,因此应当竭力避免。有人发现,在调试的时候多多关注lint的教诲,会非常有用。

“研习”并不是说毫无原则地改掉lint指出的所有问题,因为有些问题没办法改正,但你应该知道lint为什么会报错,理解它担心的问题何在。

2. 不应访问NULL指针,因为这样只会导致混乱和疯狂。

显然这句箴言抄错了,应该是“空指针”(null pointer)不是NULL指针(NULL pointer),避免人们把空指针和NULL宏混淆。除此之外,这一条无需多解释。空指针指向的位置可能是恶龙、恶魔、core dump,以及数不清的邪恶生物,如果你惊了它们的美梦,它们就会在程序里肆虐横行。空指针并不会指向0或任何类型,尽管一些老旧的代码会做这种假设。

3. 不应将所有函数参数都强制转换为期待的类型,即使你认为无需如此固执,才能避免迟早会到来的报应。

程序员应当懂得所用语言的类型结构,才能免遭不幸。与一些人的认知不同,int和long并不是同一种类型。历史上曾有非常短暂的一段时期,int和long的大小和表示是相同的,但有人偏偏笃信这一点,而且这种观点还会一直延续,即使在64位计算机已经流行的现在。

而且,与那些住在污染的东方沼泽(指Unix的诞生地贝尔实验室)的人们的信仰不同,NULL其实并不是指针类型,作为函数参数使用时,必须强制转换成正确的类型才可以。

(先知Ansi C的教诲——NULL可以看作是void *类型——经常被人们曲解和误解。先知只是给出了一种特殊的解释。而正确的程序必须自己从类型的丛林中找到正确的路,而不能靠这个特殊解释来解决一切问题。不管怎样,创世神Dmr(C语言的作者丹尼斯·里奇)为C语言创造了许多种指针,而不是仅有一种,因此我们才可以把先知的NULL转换成需要的类型。)

有人可能会认为,有了新的祝福“原型”,我们就不再需要谨慎处理参数类型。但并非如此。首先,在处理诘屈聱牙的可变参数时,你又会遇到同样的问题,而没有经过严格参数类型洗礼的人很容易就会掉入陷阱。其次,聪明的人已经发现,过度依赖于原型会为许多奇怪的错误敞开大门,而且一些人的确希望官方能正式发布原型功能用于错误检查,但它不应该进行隐式类型转换。最后,依赖原型会给如今的现实世界带来巨大的麻烦,因为许多人还在使用旧方法,还有很多旧编译器,没人知道代码明天会在何种机器上运行。

4. 如果头文件没有给库函数定义返回类型,开发者应该谨慎地自行定义,以避免对程序造成伤害。

先知Ansi C还以她的智慧教导我们,你应当鞭笞供应商,以驱逐之痛要求他们提供库函数的头文件。毕竟,只有他们才知道使用他们的魔法的正确方式。

先知还说,尝试自己给函数添加定义是不智之举,会坠入无尽bug的地狱。

5. 应当检查所有字符串(以及所有数组)的数组边界,因为肯定有人会在该输入 foo 的地方输入 supercalifragilisticexpialidocious。

正如戒律中提到的超长字符串,这一条戒律的结论就是永远不要使用gets(),因为它是魔鬼的工具。你的接口应当永远将数组边界传达给仆人(指函数),若仆人不遵从,就应当发配到删除之地,使其永远不能为恶。

6. 如果一个函数声称在遇到问题时会返回错误码,那么程序员应当检查错误码,即使这样做会让代码量变成三倍。如果你认为“不会发生在我头上”,那么神一定会惩罚你的傲慢。

真正的信徒都希望更好的错误机制,因为显式检查返回代码非常麻烦,不检查则是最大的诱惑。但在遥远的救赎之日到来之前,你必须耐心谨慎地走过崎岖的小路,否则无论是供应商、机器还是软件,都会在你论文答辩或客户交付日前一天晚上为你送上意想不到的礼物。

有时,比如stdio的ferror(),你可以把错误检查推迟到最后,等收到所有结果后再进行。这样通常可以带来更短、更干净的代码。而且,即使是最狂热的信徒,对于不容失败的函数,也应当进行严谨判断……但要注意,强制转换成void是一柄双刃剑。

7. 应当学习库,尽量不要重新造轮子,因为库的代码更短、更易懂,能让开发者更快乐、更有效率。

数不清的异教徒对于库持有轻蔑的态度,并且迷信自己能做得更好(“效率更高”)。C库的确有一些功能写得不好,但使用库远远要比自己发明方形的轮子要快、要容易。但是要非常了解库能做什么、不能做什么,避免使用不可靠的功能。

8. 不管喜不喜欢,开发者应当使用1TBR风格,让程序的目录和结构能被同事理解。开发者的创造力应该放在解决问题上,而不是放在制造理解障碍上。

这条戒律给那些不了解古谚语的新手和皈依者造成了一些怀疑。1TBR指的是第一代先知布莱恩·克尼汉和丹尼斯·里奇在他们的文章中演示的风格(即K&R风格的变种)。很多人批评这种风格很难用,但实际上它只是有点难学,一旦学会之后就非常清晰易懂,非要说缺点的话,就是有点容易出错而已。

也许你会认为你自己的大括号风格写的程序更干净,但你的继任者不会感谢你,而是会诅咒你,而且这些诅咒会传到你的下一个雇主。许多传统之所以存在是因为很多人都接受它们,进而减少了摩擦、提高了生产力,至于是否是最佳选择根本不重要。大括号风格也是如此。

9. 外部标识符的前六个字符应该是唯一的,尽管这一条很烦人,而且似乎历史悠久,但它可以在你需要在旧的系统上运行程序时,避免你抓狂。

尽管一些狂热者会说“已经2022年了,这一条早就过时了,不需要照做”,但实际上世界上还有很多很多古老的系统,很难说你的下一份工作不会遇到这种系统。如果你漫不经心,它就会趁虚而入。打起精神来吧。

不过,标识符没有必要限制在六个字符以下。唯一的要求就是前六个字符必须唯一。这并不是太难。

10. 开发者应该与那些声称“全世界都是VAX机”的异端保持距离,不要与他们交往,因为你的程序可能比机器还要长寿。

与这一条类似的说法还有:“全世界都是Sun机器”或“全世界都是386”(特别是后者,是撒旦的发明),甚至可以应用到一切。注意,另一种更隐晦、更可怕的说法是“全世界都是32位机器”,虽然时至今日这句话依然并非虚言,但总有一天会遭到反噬。

— 推荐阅读 —

3ff1be06fa0dea5245ed429303391d35.jpeg

Logo

20年前,《新程序员》创刊时,我们的心愿是全面关注程序员成长,中国将拥有新一代世界级的程序员。20年后的今天,我们有了新的使命:助力中国IT技术人成长,成就一亿技术人!

更多推荐