代码风格
这是一个简短的文档,节选改编自 linux 内核的首选代码风格。代码风格是因人而异的,
而且我不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则
那样,我也希望在绝大多数事上保持这种的态度。请 (在写代码时) 至少考虑一下这里
的代码风格。
不管怎样,现在我们开始:
1) 缩进
制表符是 4 个字符,所以缩进也是 4 个字符。
不要把多个语句放在一行里,除非你有什么东西要隐藏:
也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读
的表达式。
2) 把长的行和字符串打散
代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
每一行的长度的限制是 80 列,我们强烈建议您遵守这个惯例。
3) 大括号和空格的放置
C 语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放
置策略并没有多少技术上的原因,不过首选的方式,就像 Kernighan 和 Ritchie 展示
给我们的,是把起始大括号放在行尾,而把结束大括号放在行首,所以:
.. code-block:: c
if (x is true) {
we do y
}
这适用于所有的非函数语句块 (if, switch, for, while, do)。
注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是 do 语
句中的 “while” 或者 if 语句中的 “else”,像这样:
.. code-block:: c
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
也请注意这种大括号的放置方式也能使空 (或者差不多空的) 行的数量最小化,同时不
失可读性。因此,由于你的屏幕上的新行是不可再生资源 (想想 25 行的终端屏幕),你
将会有更多的空行来放置注释。
当只有一个单独的语句的时候,不用加不必要的大括号。
.. code-block:: c
if (condition)
action();
和
.. code-block:: c
if (condition)
do_this();
else
do_that();
这并不适用于只有一个条件分支是单语句的情况;这时所有分支都要使用大括号:
.. code-block:: c
if (condition) {
do_this();
do_that();
} else {
otherwise();
}
3.1) 空格
Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关键字。(大多数) 关键字
后要加一个空格。值得注意的例外是 sizeof, typeof, alignof 和 attribute,这
些关键字某些程度上看起来更像函数 (它们在 Linux 里也常常伴随小括号而使用,尽管
在 C 里这样的小括号不是必需的,就像 struct fileinfo info;
声明过后的
sizeof info
)。
所以在这些关键字之后放一个空格::
if, switch, case, for, do, while
但是不要在 sizeof, typeof, alignof 或者 attribute 这些关键字之后放空格。
例如,
.. code-block:: c
s = sizeof(struct file);
不要在小括号里的表达式两侧加空格。这是一个 反例 :
.. code-block:: c
s = sizeof( struct file );
在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符::
= + - < > * / % | & ^ <= >= == != ? :
但是一元操作符后不要加空格::
& * + - ~ ! sizeof typeof alignof __attribute__ defined
后缀自加和自减一元操作符前不加空格::
++ --
前缀自加和自减一元操作符后不加空格::
++ --
.
和 ->
结构体成员操作符前后不加空格。
4) 命名
C 是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同,
C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会
称那个变量为 tmp
,这样写起来会更容易,而且至少不会令其难于理解。
不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的
名字。称一个全局函数为 foo
是一个难以饶恕的错误。
全局变量 (只有当你 真正 需要它们的时候再用它) 需要有一个具描述性的名字,就
像全局函数。如果你有一个可以计算活动用户数量的函数,你应该叫它
count_active_users()
或者类似的名字,你不应该叫它 cntuser()
。
在函数名中包含函数类型 (所谓的匈牙利命名法) 是脑子出了问题——编译器知道那些类
型而且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题
的程序。
本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计
数器,它应该被称为 i
。叫它 loop_counter
并无益处,如果它没有被误解的
可能的话。类似的, tmp
可以用来称呼任意类型的临时变量。
5) 函数
函数应该简短而漂亮,并且只完成一件事情。函数应该只做一件事情,而且把它做好。
一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理
论上很简单的只有一个很长 (但是简单) 的 case 语句的函数,而且你需要在每个 case
里做很多很小的事情,这样的函数尽管很长,但也是可以的。
不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能
甚至搞不清楚这个函数的目的,你应该严格遵守前面提到的长度限制。使用辅助函数,
并为之取个具描述性的名字 (如果你觉得它们的性能很重要的话,可以让编译器内联它
们,这样的效果往往会比你写一个复杂函数的效果要好。)
函数的另外一个衡量标准是本地变量的数量。此数量不应超过 5-10 个,否则你的函数
就有问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松
的同时跟踪 7 个不同的事物,如果再增多的话,就会糊涂了。即便你聪颖过人,你也可
能会记不清你 2 个星期前做过的事情。