日期:2014-05-16  浏览次数:20754 次

Linux kernel coding style.

Linux内核代码风格

这是一个简短的文档,描述了linux内核的首选代码风格。代码风格是因人而异的,而且我
不愿意把我的观点强加给任何人,不过这里所讲述的是我必须要维护的代码所遵守的风格,
并且我也希望绝大多数其他代码也能遵守这个风格。请在写代码时至少考虑一下本文所述的
风格。

首先,我建议你打印一份GNU代码规范,然后不要读它。烧了它,这是一个具有重大象征性
意义的动作。

不管怎样,现在我们开始:


??? ???? 第一章:缩进

制表符是8个字符,所以缩进也是8个字符。有些异端运动试图将缩进变为4(乃至2)个字符
深,这几乎相当于尝试将圆周率的值定义为3。

理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的屏幕
连续看了20小时之后,你将会发现大一点的缩进会使你更容易分辨缩进。

现在,有些人会抱怨8个字符的缩进会使代码向右边移动的太远,在80个字符的终端屏幕上
就很难读这样的代码。这个问题的答案是,如果你需要3级以上的缩进,不管用何种方式你
的代码已经有问题了,应该修正你的程序。

简而言之,8个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太深的
时候可以给你警告
。留心这个警告。

在switch语句中消除多级缩进的首选的方式是让“switch”和从属于它的“case”标签对齐于同
一列,而不要“两次缩进”“case”标签。比如:

??? switch (suffix) {
??? case 'G':
??? case 'g':
??? ??? mem <<= 30;
??? ??? break;
??? case 'M':
??? case 'm':
??? ??? mem <<= 20;
??? ??? break;
??? case 'K':
??? case 'k':
??? ??? mem <<= 10;
??? ??? /* fall through */
??? default:
??? ??? break;
??? }


不要把多个语句放在一行里 ,除非你有什么东西要隐藏:

??? if (condition) do_this;
??? ? do_something_everytime;

也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读的表
达式。

除了注释、文档和Kconfig之外,不要使用空格来缩进,前面的例子是例外,是有意为之。

选用一个好的编辑器,不要在行尾留空格。


??? ??? 第二章:把长的行和字符串打散

代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。

每一行的长度的限制是80列 ,我们强烈建议您遵守这个惯例。

长于80列的语句要打散成有意义的片段。每个片段要明显短于原来的语句,而且放置的位置
也明显的靠右。同样的规则也适用于有很长参数列表的函数头。长字符串也要打散成较短的
字符串。唯一的例外是超过80列可以大幅度提高可读性并且不会隐藏信息的情况。

void fun(int a, int b, int c)
{
??? if (condition)
??? ??? printk(KERN_WARNING "Warning this is a long printk with "
??? ??? ??? ??? ??? ??? "3 parameters a: %u b: %u "
??? ??? ??? ??? ??? ??? "c: %u \n", a, b, c);
??? else
??? ??? next_statement;
}

??? ??? 第三章:大括号和空格的放置

C语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放置策
略并没有多少技术上的原因,不过首选的方式,就像Kernighan和Ritchie展示给我们的,是
起始大括号放在行尾,而把结束大括号放在行首 ,所以:

??? if (x is true) {
??? ??? we do y
??? }

这适用于所有的非函数语句块(if、switch、for、while、do)。比如:

??? switch (action) {
??? case KOBJ_ADD:
??? ??? return "add";
??? case KOBJ_REMOVE:
??? ??? return "remove";
??? case KOBJ_CHANGE:
??? ??? return "change";
??? default:
??? ??? return NULL;
??? }

不过,有一个例外,那就是函数:函数的起始大括号放置于下一行的开头 ,所以:

??? int function(int x)
??? {
??? ??? body of function
??? }

全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过所有思维健全的人都知道(
a)K&R是_正确的_,并且(b)K&R是正确的。此外,不管怎样函数都是特殊的(在C语言中
,函数是不能嵌套的)。

注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是do语句中的
“while”或者if语句中的“else”,像这样:

??? do {
??? ??? body of do-loop
??? } while (condition);



??? if (x == y) {
??? ??? ..
??? } else if (x > y) {
??? ??? ...
??? } else {
??? ??? ....
??? }

理由:K&R。

也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可
读性。因此,由于你的屏幕上的新行是不可再生资源(想想25行的终端屏幕),你将会有更
多的空行来放置注释。

当只有一个单独的语句的时候,不用加不必要的大括号

if (condition)
??? action();

这点不适用于本身为某个条件语句的一个分支的单独语句。这时需要在两个分支里都使用大
括号


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__这些关键字之后放空格。例如,
??? s = sizeof(struct file);