Linux Kernel Coding Style - 适合学C的初学者学习.老手参考
file: /usr/src/linux/Documentation/CodingStyle
Initial translation, 9/28 1997, by
syc@cc.ntu.edu.tw 萧永庆
------------------------------------------------------------------
Linux kernel 程式设计规范
这是一篇描述linux kernel所期望的程式设计风格的短文. 程式风格是
因人而异的, 所以我不愿意_强迫_他人接受我的看法, 但是现在我们是讨
论一份我必须维护的程式码,而我也偏好在其它方面使用这种风格.请你至少
考虑这里所作的论点.
首先, 我想建议你印一份GNU程式设计风格指南出来, 然后千万不要读它.
把它烧掉, 它实在是一篇充满代号的咒文.
总而言之, 这就是我要的这样子:
第一章: 缩格
Tab就是八个空白, 所以缩格也就是八格. 有个邪说想把缩格
设成4(甚至2)格, 这就像是尝试把PI的值定义成3一样.
按: 缩格背后的真正意义是用来清楚的界定一个控制区块的开始与结束.
特别是当你已经盯了连续20小时的萤幕的时候, 你就会发现使用大缩格
是如何有效的发挥它应有的功能.
到此为止,有些人会宣称缩8格会让程式码移到太右边去, 使得在80个字宽的
终端机萤幕下非常的难以阅读. 我的回答是如果你需要多过3层的缩格,
无论如何你大概已经搞砸了, 应该要修改你的程式才对.
简端的说,八格的缩格较容易阅读, 并且,当你的副程式巢状太深的话,
有个附加的预警效果. 要注意这个警告!
第二章: 括号的摆法
C设计风格中另外常被讨论的就是括号的位置. 不像缩格的案例, 选择括号的
摆设没什么特别的技术上的理由, 但是我较篇好的方式, 就像先贤Kernighan
和Ritchie所示范给我们看的样子, 是把左大括号放在行尾, 然后右大括号
放在一行的最前面, 就是这样子:
if (x 为 真) {
执行步骤 y
}
不过, 有一个例外, 就是函式: 函式的左大括号放在次一行的开头, 如下:
int function(int x)
{
函式的内容
}
全世界的邪教徒会宣称这个例外是...反正就是...不一致,但是所有思想正确
的人都知道及
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
按: K&R.
此外, 注意这种摆法使得在不失去可读性下, 空白行(或者几乎空白的行)的
数量最少. 因此, 当萤幕的行数有限的时候(这里请考虑25行的萤幕), 你有
较多的空行可以放注解.
第三章: 命名
C是一个非常简洁的语言, 所以你的命名也要一样. 不像Modula-2和Pascal
的程式设计者, C程式设计者不会用像ThisVariableIsATemporaryCounter
这样滑稽的名字. 一个C程式设计者会叫这个变数"tmp", 不仅较容易写,
并且至少不会比较难以理解.
不过, 虽然不赞成使用混杂大小写的名字, 但是全域变数一定须要具有
描述性的名字. 叫一个全域函式 "foo" 是一种故意犯错的行为.
全域变数 (仅在必要的时后才使用之)须要有描述性的名字, 就像全域函式一样.
如果你有一个函式用来数活跃的(active)使用者,你应该称之为
"count_active_users()" 或者类似的名字, 不应该称为 "cntusr()"
把函式的型别编进名字里面(所谓的匈牙利表示法, Hungarian notation)是
头壳坏去的行为 - 无论如何编译器永远知道这些形别,而且可以帮你检查,
这种编码只有令程式设计者更加搞不清楚而已. 难怪MicroSoft制造的
程式都有很多bug.
区域变数名字应该要简短,并且恰到好处. 如果你有一些随意的整数回圈计数器
(loop counter), 它应该称之为 "i". 如果没有被混用的困扰的话, 叫它
"loop_counter" 是没有效率的, 同样的, "tmp" 可以是任何的型别的变数,
只要是这个变数用来储存一些暂时的资料.
如果你怕搞混了你的区域变数的名字,那你遇到另一个问题, 被称为
函式成长贺尔蒙失调症. 请参考下一章说明.
第四章: 函式
函式必须短小可爱, 并且只做一件事. 它们应该能够塞进一或两页
的萤幕里去(我们都知道ISO/ANSI标准萤幕大小是80x24), 且只做一件
事, 并且要做的好.
一个函式的(可允许的)最大长度是和其复杂度及缩格的程度成反比. 所以如
果你有一个观念上简单的函式,却是一个长的(但是简单的)case叙述, 其
中你须要对许多不同的情况做许多的小处理, 那么函式长一点没有关系.
不过,如果你有一个复杂的函式, 而你觉得可能一般程度的高一学生就
无法了解这个函式在干麻, 你可能更需要更严格的遵守最大长度的限制.
使用名字较有意义的辅助函式(helper functions) (如果这个函式对效率
的要求很高的话, 你可以要求编译器把这些辅助函式当作in-line function
展开, 而且编译器可能可以做的比你自己手工做来的好)
另外一个评量函式的方法是区域变数的数量. 它们不应该超过5-10个,
不然你可能做错了什么事. 重新构思一下这个函式, 然后把它切成几个
小块. 人脑一般可以轻易的处理七件事,超过这个数量就会搞乱了.
你知道你很聪明, 但是两个礼拜后你可能还想了解你现在做了什么.
第五章: 注解
注解是件好事, 但是也有过份注解的危险. 绝对不要在注解内试着解释
你的码是如何工作的: 这还不如把程式写得清楚点, 一看就知道它在干麻,
而且解释一段乱写的码是件浪废时间的事.
大致而言, 你要你的注解说明你的程式做了什么, 而不是如何做.
并且, 试着避免在函式里面放注释: 如果你的程式复杂到需要
对部份的内容做注解, 你可能需要再花点时间重看第四章. 你
可以放些小注解来解释或警告一些特别的小聪明(或丑陋的)地方,
但是尽量避免过份使用. 正确的作法应是把注解放在函式开头的地
方, 告诉他人它要作什么, 可能还要说明为什么要做这些事.
第六章: 你把程式弄的乱七八糟了
没关系, 我们都会遇到这种问题. 可能有unix老手已经告诉
过你 "GNU emacs" 可以自动的帮你重排C 的程式码, 而你也发
现它的确会做, 但是它的预设值有点令人不满意(事实上, 这些值
还比打字乱打糟糕 - 在GNU emacs上任意的乱打还是造不出好程式的)
所以, 你可以把GNU emacs丢掉,或者设定一些较合理的预设值. 后者
可以把下面这些码放到你的.emacs档达成:
(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(c-set-style "K&R")
(setq c-basic-offset 8))
这样定义了 M-x linux-c-mode 指令. 当你 hack 某个模组时, 如果
你在前两行的任意地方放 -*- linux-c -*- 这个字串, 这个模式就
会自动的起动. 同时, 你也可能想要加这行:
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))
到你的.emacs档去, 如果当你编辑/usr/src/linux下的程式档的时后, 想让
linux-c-mode自动起动的话.
不过仅管你还是不能利用emacs作合理的重排的话, 你还没绝望: 使用 "indent".
这里又遇到同样的问题. GNU indent和GNU emacs有同样的白痴设定, 这就
是为什么你须要给它一些命令列选项的原因. 还好, 这不会太麻烦, 因为
连GNU indent的作者也体认到K&R的权威性 (GNU的人不坏, 他们在这方
面只是被严重的误导了罢了), 所以你只要给indent这样的选项 "-kr -i8"
即可(表示 "K&R, 八格的缩格").
"indent" 有许多的选项,特别是预到重排注解的时候, 你可能需要看一下
使用手册. 不过要记得: "indent" 不是修理不良程式码的工具.