diff options
author | Andy Deng <theandy.deng@gmail.com> | 2017-01-25 12:14:32 +0800 |
---|---|---|
committer | Jonathan Corbet <corbet@lwn.net> | 2017-01-26 15:30:00 -0700 |
commit | 0dacbc9df5c9fc6037060fbb12c1d7da80f5b580 (patch) | |
tree | bab38f2bed0c750c641d5e384a90b6f4d09b066e | |
parent | 9e5e74e61ce8615d4105b2651f6b7d46434014f2 (diff) | |
download | linux-0dacbc9df5c9fc6037060fbb12c1d7da80f5b580.tar.gz linux-0dacbc9df5c9fc6037060fbb12c1d7da80f5b580.tar.bz2 linux-0dacbc9df5c9fc6037060fbb12c1d7da80f5b580.zip |
zh_CN/CodingStyle: Convert to ReST markup
This commit applies all changes from the English version, and should
be able to work with the documentation build system.
Signed-off-by: Andy Deng <theandy.deng@gmail.com>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
-rw-r--r-- | Documentation/translations/zh_CN/CodingStyle | 788 |
1 files changed, 462 insertions, 326 deletions
diff --git a/Documentation/translations/zh_CN/CodingStyle b/Documentation/translations/zh_CN/CodingStyle index 45b8fc9ef8ea..1466aa64b8b4 100644 --- a/Documentation/translations/zh_CN/CodingStyle +++ b/Documentation/translations/zh_CN/CodingStyle @@ -6,51 +6,61 @@ Chinese maintainer for help. Contact the Chinese maintainer, if this translation is outdated or there is problem with translation. Chinese maintainer: Zhang Le <r0bertz@gentoo.org> + --------------------------------------------------------------------- -Documentation/process/coding-style.rst的中文翻译 - -如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可 -以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。 - -中文版维护者: 张乐 Zhang Le <r0bertz@gentoo.org> -中文版翻译者: 张乐 Zhang Le <r0bertz@gentoo.org> -中文版校译者: 王聪 Wang Cong <xiyou.wangcong@gmail.com> - wheelz <kernel.zeng@gmail.com> - 管旭东 Xudong Guan <xudong.guan@gmail.com> - Li Zefan <lizf@cn.fujitsu.com> - Wang Chen <wangchen@cn.fujitsu.com> + +Documentation/process/coding-style.rst 的中文翻译 + +如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话, +也可以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版 +维护者:: + + 中文版维护者: 张乐 Zhang Le <r0bertz@gentoo.org> + 中文版翻译者: 张乐 Zhang Le <r0bertz@gentoo.org> + 中文版校译者: 王聪 Wang Cong <xiyou.wangcong@gmail.com> + wheelz <kernel.zeng@gmail.com> + 管旭东 Xudong Guan <xudong.guan@gmail.com> + Li Zefan <lizf@cn.fujitsu.com> + Wang Chen <wangchen@cn.fujitsu.com> + 以下为正文 + --------------------------------------------------------------------- - Linux内核代码风格 +Linux 内核代码风格 +========================= -这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的,而且我 -不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则那样,我也 -希望在绝大多数事上保持这种的态度。请(在写代码时)至少考虑一下这里的代码风格。 +这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的, +而且我不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则 +那样,我也希望在绝大多数事上保持这种的态度。请 (在写代码时) 至少考虑一下这里 +的代码风格。 -首先,我建议你打印一份 GNU 代码规范,然后不要读。烧了它,这是一个具有重大象征性意义 -的动作。 +首先,我建议你打印一份 GNU 代码规范,然后不要读。烧了它,这是一个具有重大象征 +性意义的动作。 不管怎样,现在我们开始: - 第一章:缩进 +1) 缩进 +-------------- + +制表符是 8 个字符,所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4 (甚至 +2!) 字符深,这几乎相当于尝试将圆周率的值定义为 3。 -制表符是 8 个字符,所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4(甚至 2!) -个字符深,这几乎相当于尝试将圆周率的值定义为 3。 +理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的 +屏幕连续看了 20 小时之后,你将会发现大一点的缩进会使你更容易分辨缩进。 -理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的屏幕 -连续看了 20 小时之后,你将会发现大一点的缩进会使你更容易分辨缩进。 +现在,有些人会抱怨 8 个字符的缩进会使代码向右边移动的太远,在 80 个字符的终端 +屏幕上就很难读这样的代码。这个问题的答案是,如果你需要 3 级以上的缩进,不管用 +何种方式你的代码已经有问题了,应该修正你的程序。 -现在,有些人会抱怨 8 个字符的缩进会使代码向右边移动的太远,在 80 个字符的终端屏幕上 -就很难读这样的代码。这个问题的答案是,如果你需要 3 级以上的缩进,不管用何种方式你 -的代码已经有问题了,应该修正你的程序。 +简而言之,8 个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太 +深的时候可以给你警告。留心这个警告。 -简而言之,8 个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太深的 -时候可以给你警告。留心这个警告。 +在 switch 语句中消除多级缩进的首选的方式是让 ``switch`` 和从属于它的 ``case`` +标签对齐于同一列,而不要 ``两次缩进`` ``case`` 标签。比如: -在 switch 语句中消除多级缩进的首选的方式是让 “switch” 和从属于它的 “case” 标签 -对齐于同一列,而不要 “两次缩进” “case” 标签。比如: +.. code-block:: c switch (suffix) { case 'G': @@ -71,39 +81,49 @@ Documentation/process/coding-style.rst的中文翻译 不要把多个语句放在一行里,除非你有什么东西要隐藏: +.. code-block:: c + if (condition) do_this; do_something_everytime; -也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读的表 -达式。 +也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读 +的表达式。 -除了注释、文档和 Kconfig 之外,不要使用空格来缩进,前面的例子是例外,是有意为之。 +除了注释、文档和 Kconfig 之外,不要使用空格来缩进,前面的例子是例外,是有意为 +之。 选用一个好的编辑器,不要在行尾留空格。 - 第二章:把长的行和字符串打散 +2) 把长的行和字符串打散 +------------------------------ 代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。 每一行的长度的限制是 80 列,我们强烈建议您遵守这个惯例。 -长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性,并且不会隐藏 -信息。子片段要明显短于母片段,并明显靠右。这同样适用于有着很长参数列表的函数头。 -然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这将导致无法 grep 这些 -信息。 +长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性,并且不 +会隐藏信息。子片段要明显短于母片段,并明显靠右。这同样适用于有着很长参数列表 +的函数头。然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这样就 +很难对它们 grep。 + - 第三章:大括号和空格的放置 +3) 大括号和空格的放置 +------------------------------ -C语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放置策 -略并没有多少技术上的原因,不过首选的方式,就像 Kernighan 和 Ritchie 展示给我们的, -是把起始大括号放在行尾,而把结束大括号放在行首,所以: +C 语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放 +置策略并没有多少技术上的原因,不过首选的方式,就像 Kernighan 和 Ritchie 展示 +给我们的,是把起始大括号放在行尾,而把结束大括号放在行首,所以: + +.. code-block:: c if (x is true) { we do y } -这适用于所有的非函数语句块(if、switch、for、while、do)。比如: +这适用于所有的非函数语句块 (if, switch, for, while, do)。比如: + +.. code-block:: c switch (action) { case KOBJ_ADD: @@ -118,17 +138,21 @@ C语言风格中另外一个常见问题是大括号的放置。和缩进大小 不过,有一个例外,那就是函数:函数的起始大括号放置于下一行的开头,所以: +.. code-block:: c + int function(int x) { body of function } -全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过所有思维健全的人都知道 -(a) K&R 是 _正确的_,并且 (b) K&R 是正确的。此外,不管怎样函数都是特殊的(C -函数是不能嵌套的)。 +全世界的异端可能会抱怨这个不一致性是... 呃... 不一致的,不过所有思维健全的人 +都知道 (a) K&R 是 **正确的** 并且 (b) K&R 是正确的。此外,不管怎样函数都是特 +殊的 (C 函数是不能嵌套的)。 + +注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是 do 语 +句中的 "while" 或者 if 语句中的 "else",像这样: -注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是 do 语句中的 -“while” 或者 if 语句中的 “else”,像这样: +.. code-block:: c do { body of do-loop @@ -136,6 +160,8 @@ C语言风格中另外一个常见问题是大括号的放置。和缩进大小 和 +.. code-block:: c + if (x == y) { .. } else if (x > y) { @@ -146,17 +172,21 @@ C语言风格中另外一个常见问题是大括号的放置。和缩进大小 理由:K&R。 -也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可 -读性。因此,由于你的屏幕上的新行是不可再生资源(想想 25 行的终端屏幕),你将会有更 -多的空行来放置注释。 +也请注意这种大括号的放置方式也能使空 (或者差不多空的) 行的数量最小化,同时不 +失可读性。因此,由于你的屏幕上的新行是不可再生资源 (想想 25 行的终端屏幕),你 +将会有更多的空行来放置注释。 当只有一个单独的语句的时候,不用加不必要的大括号。 +.. code-block:: c + if (condition) action(); 和 +.. code-block:: c + if (condition) do_this(); else @@ -164,6 +194,8 @@ C语言风格中另外一个常见问题是大括号的放置。和缩进大小 这并不适用于只有一个条件分支是单语句的情况;这时所有分支都要使用大括号: +.. code-block:: c + if (condition) { do_this(); do_that(); @@ -171,88 +203,103 @@ C语言风格中另外一个常见问题是大括号的放置。和缩进大小 otherwise(); } - 3.1:空格 +3.1) 空格 +******************** -Linux 内核的空格使用方式(主要)取决于它是用于函数还是关键字。(大多数)关键字后 -要加一个空格。值得注意的例外是 sizeof、typeof、alignof 和 __attribute__,这些 -关键字某些程度上看起来更像函数(它们在 Linux 里也常常伴随小括号而使用,尽管在 C 里 -这样的小括号不是必需的,就像 “struct fileinfo info” 声明过后的 “sizeof info”)。 +Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关键字。(大多数) 关键字 +后要加一个空格。值得注意的例外是 sizeof, typeof, alignof 和 __attribute__,这 +些关键字某些程度上看起来更像函数 (它们在 Linux 里也常常伴随小括号而使用,尽管 +在 C 里这样的小括号不是必需的,就像 ``struct fileinfo info;`` 声明过后的 +``sizeof info``)。 -所以在这些关键字之后放一个空格: +所以在这些关键字之后放一个空格:: if, switch, case, for, do, while -但是不要在 sizeof、typeof、alignof 或者 __attribute__ 这些关键字之后放空格。例如, +但是不要在 sizeof, typeof, alignof 或者 __attribute__ 这些关键字之后放空格。 +例如, + +.. code-block:: c s = sizeof(struct file); -不要在小括号里的表达式两侧加空格。这是一个反例: +不要在小括号里的表达式两侧加空格。这是一个 **反例** : + +.. code-block:: c s = sizeof( struct file ); -当声明指针类型或者返回指针类型的函数时,“*” 的首选使用方式是使之靠近变量名或者函 -数名,而不是靠近类型名。例子: +当声明指针类型或者返回指针类型的函数时, ``*`` 的首选使用方式是使之靠近变量名 +或者函数名,而不是靠近类型名。例子: + +.. code-block:: c char *linux_banner; unsigned long long memparse(char *ptr, char **retptr); char *match_strdup(substring_t *s); -在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符: +在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符:: = + - < > * / % | & ^ <= >= == != ? : -但是一元操作符后不要加空格: +但是一元操作符后不要加空格:: & * + - ~ ! sizeof typeof alignof __attribute__ defined -后缀自加和自减一元操作符前不加空格: +后缀自加和自减一元操作符前不加空格:: ++ -- -前缀自加和自减一元操作符后不加空格: +前缀自加和自减一元操作符后不加空格:: ++ -- -‘.’ 和 “->” 结构体成员操作符前后不加空格。 +``.`` 和 ``->`` 结构体成员操作符前后不加空格。 -不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你 -就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器就不 -会移除已经加入的空白,就像你故意留下一个只有空白的行。包含行尾空白的行就这样产 -生了。 +不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后 +你就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器 +就不会移除已经加入的空白,就像你故意留下一个只有空白的行。包含行尾空白的行就 +这样产生了。 -当git发现补丁包含了行尾空白的时候会警告你,并且可以应你的要求去掉行尾空白;不过 -如果你是正在打一系列补丁,这样做会导致后面的补丁失败,因为你改变了补丁的上下文。 +当 git 发现补丁包含了行尾空白的时候会警告你,并且可以应你的要求去掉行尾空白; +不过如果你是正在打一系列补丁,这样做会导致后面的补丁失败,因为你改变了补丁的 +上下文。 - 第四章:命名 +4) 命名 +------------------------------ -C是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同,C 程序员 -不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会称那个变量 -为 “tmp”,这样写起来会更容易,而且至少不会令其难于理解。 +C 是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同, +C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会 +称那个变量为 ``tmp`` ,这样写起来会更容易,而且至少不会令其难于理解。 -不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的名字 -。称一个全局函数为 “foo” 是一个难以饶恕的错误。 +不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的 +名字。称一个全局函数为 ``foo`` 是一个难以饶恕的错误。 -全局变量(只有当你真正需要它们的时候再用它)需要有一个具描述性的名字,就像全局函 -数。如果你有一个可以计算活动用户数量的函数,你应该叫它 “count_active_users()” -或者类似的名字,你不应该叫它 “cntuser()”。 +全局变量 (只有当你 **真正** 需要它们的时候再用它) 需要有一个具描述性的名字,就 +像全局函数。如果你有一个可以计算活动用户数量的函数,你应该叫它 +``count_active_users()`` 或者类似的名字,你不应该叫它 ``cntuser()`` 。 -在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型而 -且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题的程序。 +在函数名中包含函数类型 (所谓的匈牙利命名法) 是脑子出了问题——编译器知道那些类 +型而且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题 +的程序。 -本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计数器 -,它应该被称为 “i”。叫它 “loop_counter” 并无益处,如果它没有被误解的可能的话。 -类似的,“tmp” 可以用来称呼任意类型的临时变量。 +本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计 +数器,它应该被称为 ``i`` 。叫它 ``loop_counter`` 并无益处,如果它没有被误解的 +可能的话。类似的, ``tmp`` 可以用来称呼任意类型的临时变量。 -如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综合症 -。请看第六章(函数)。 +如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综 +合症。请看第六章 (函数)。 - 第五章:Typedef +5) Typedef +----------- -不要使用类似 “vps_t” 之类的东西。 +不要使用类似 ``vps_t`` 之类的东西。 -对结构体和指针使用 typedef 是一个错误。当你在代码里看到: +对结构体和指针使用 typedef 是一个 **错误** 。当你在代码里看到: + +.. code-block:: c vps_t a; @@ -260,75 +307,89 @@ C是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pasca 相反,如果是这样 +.. code-block:: c + struct virtual_container *a; -你就知道 “a” 是什么了。 +你就知道 ``a`` 是什么了。 -很多人认为 typedef “能提高可读性”。实际不是这样的。它们只在下列情况下有用: +很多人认为 typedef ``能提高可读性`` 。实际不是这样的。它们只在下列情况下有用: - (a) 完全不透明的对象(这种情况下要主动使用 typedef 来隐藏这个对象实际上是什么)。 + (a) 完全不透明的对象 (这种情况下要主动使用 typedef 来 **隐藏** 这个对象实际上 + 是什么)。 - 例如:“pte_t” 等不透明对象,你只能用合适的访问函数来访问它们。 + 例如: ``pte_t`` 等不透明对象,你只能用合适的访问函数来访问它们。 - 注意!不透明性和“访问函数”本身是不好的。我们使用 pte_t 等类型的原因在于真的是 - 完全没有任何共用的可访问信息。 + .. note:: - (b) 清楚的整数类型,如此,这层抽象就可以帮助消除到底是 “int” 还是 “long” 的混淆。 + 不透明性和 "访问函数" 本身是不好的。我们使用 pte_t 等类型的原因在于真 + 的是完全没有任何共用的可访问信息。 + + (b) 清楚的整数类型,如此,这层抽象就可以 **帮助** 消除到底是 ``int`` 还是 + ``long`` 的混淆。 u8/u16/u32 是完全没有问题的 typedef,不过它们更符合类别 (d) 而不是这里。 - 再次注意!要这样做,必须事出有因。如果某个变量是 “unsigned long“,那么没有必要 + .. note:: + + 要这样做,必须事出有因。如果某个变量是 ``unsigned long`` ,那么没有必要 typedef unsigned long myflags_t; - 不过如果有一个明确的原因,比如它在某种情况下可能会是一个 “unsigned int” 而在 - 其他情况下可能为 “unsigned long”,那么就不要犹豫,请务必使用 typedef。 + 不过如果有一个明确的原因,比如它在某种情况下可能会是一个 ``unsigned int`` + 而在其他情况下可能为 ``unsigned long`` ,那么就不要犹豫,请务必使用 + typedef。 - (c) 当你使用sparse按字面的创建一个新类型来做类型检查的时候。 + (c) 当你使用 sparse 按字面的创建一个 **新** 类型来做类型检查的时候。 - (d) 和标准C99类型相同的类型,在某些例外的情况下。 + (d) 和标准 C99 类型相同的类型,在某些例外的情况下。 - 虽然让眼睛和脑筋来适应新的标准类型比如 “uint32_t” 不需要花很多时间,可是有些 - 人仍然拒绝使用它们。 + 虽然让眼睛和脑筋来适应新的标准类型比如 ``uint32_t`` 不需要花很多时间,可 + 是有些人仍然拒绝使用它们。 - 因此,Linux 特有的等同于标准类型的 “u8/u16/u32/u64” 类型和它们的有符号类型是被 - 允许的——尽管在你自己的新代码中,它们不是强制要求要使用的。 + 因此,Linux 特有的等同于标准类型的 ``u8/u16/u32/u64`` 类型和它们的有符号 + 类型是被允许的——尽管在你自己的新代码中,它们不是强制要求要使用的。 - 当编辑已经使用了某个类型集的已有代码时,你应该遵循那些代码中已经做出的选择。 + 当编辑已经使用了某个类型集的已有代码时,你应该遵循那些代码中已经做出的选 + 择。 (e) 可以在用户空间安全使用的类型。 - 在某些用户空间可见的结构体里,我们不能要求C99类型而且不能用上面提到的 “u32” - 类型。因此,我们在与用户空间共享的所有结构体中使用 __u32 和类似的类型。 + 在某些用户空间可见的结构体里,我们不能要求 C99 类型而且不能用上面提到的 + ``u32`` 类型。因此,我们在与用户空间共享的所有结构体中使用 __u32 和类似 + 的类型。 -可能还有其他的情况,不过基本的规则是永远不要使用 typedef,除非你可以明确的应用上 -述某个规则中的一个。 +可能还有其他的情况,不过基本的规则是 **永远不要** 使用 typedef,除非你可以明 +确的应用上述某个规则中的一个。 -总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们就不 -应该是一个 typedef。 +总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们 +就不应该是一个 typedef。 - 第六章:函数 +6) 函数 +------------------------------ -函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完(我们都知 -道 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好。 +函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完 (我们 +都知道 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好。 -一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理论上 -很简单的只有一个很长(但是简单)的 case 语句的函数,而且你需要在每个 case 里做 -很多很小的事情,这样的函数尽管很长,但也是可以的。 +一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理 +论上很简单的只有一个很长 (但是简单) 的 case 语句的函数,而且你需要在每个 case +里做很多很小的事情,这样的函数尽管很长,但也是可以的。 -不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能甚至 -搞不清楚这个函数的目的,你应该严格的遵守前面提到的长度限制。使用辅助函数,并为之 -取个具描述性的名字(如果你觉得它们的性能很重要的话,可以让编译器内联它们,这样的 -效果往往会比你写一个复杂函数的效果要好。) +不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能 +甚至搞不清楚这个函数的目的,你应该严格遵守前面提到的长度限制。使用辅助函数, +并为之取个具描述性的名字 (如果你觉得它们的性能很重要的话,可以让编译器内联它 +们,这样的效果往往会比你写一个复杂函数的效果要好。) -函数的另外一个衡量标准是本地变量的数量。此数量不应超过 5-10 个,否则你的函数就有 -问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松的同时跟 -踪 7 个不同的事物,如果再增多的话,就会糊涂了。即便你聪颖过人,你也可能会记不清你 -2 个星期前做过的事情。 +函数的另外一个衡量标准是本地变量的数量。此数量不应超过 5-10 个,否则你的函数 +就有问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松 +的同时跟踪 7 个不同的事物,如果再增多的话,就会糊涂了。即便你聪颖过人,你也可 +能会记不清你 2 个星期前做过的事情。 -在源文件里,使用空行隔开不同的函数。如果该函数需要被导出,它的 EXPORT* 宏应该紧贴 -在它的结束大括号之下。比如: +在源文件里,使用空行隔开不同的函数。如果该函数需要被导出,它的 **EXPORT** 宏 +应该紧贴在它的结束大括号之下。比如: + +.. code-block:: c int system_is_up(void) { @@ -336,24 +397,32 @@ C是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pasca } EXPORT_SYMBOL(system_is_up); -在函数原型中,包含函数名和它们的数据类型。虽然C语言里没有这样的要求,在 Linux 里这 -是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。 +在函数原型中,包含函数名和它们的数据类型。虽然 C 语言里没有这样的要求,在 +Linux 里这是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。 + +7) 集中的函数退出途径 +------------------------------ - 第七章:集中的函数退出途径 +虽然被某些人声称已经过时,但是 goto 语句的等价物还是经常被编译器所使用,具体 +形式是无条件跳转指令。 -虽然被某些人声称已经过时,但是 goto 语句的等价物还是经常被编译器所使用,具体形式是 -无条件跳转指令。 +当一个函数从多个位置退出,并且需要做一些类似清理的常见操作时,goto 语句就很方 +便了。如果并不需要清理操作,那么直接 return 即可。 -当一个函数从多个位置退出,并且需要做一些类似清理的常见操作时,goto 语句就很方便了。 -如果并不需要清理操作,那么直接 return 即可。 +选择一个能够说明 goto 行为或它为何存在的标签名。如果 goto 要释放 ``buffer``, +一个不错的名字可以是 ``out_free_buffer:`` 。别去使用像 ``err1:`` 和 ``err2:`` +这样的GW_BASIC 名称,因为一旦你添加或删除了 (函数的) 退出路径,你就必须对它们 +重新编号,这样会难以去检验正确性。 -理由是: +使用 goto 的理由是: - 无条件语句容易理解和跟踪 - 嵌套程度减小 -- 可以避免由于修改时忘记更新某个单独的退出点而导致的错误 -- 减轻了编译器的工作,无需删除冗余代码;) +- 可以避免由于修改时忘记更新个别的退出点而导致错误 +- 让编译器省去删除冗余代码的工作 ;) + +.. code-block:: c int fun(int a) { @@ -369,41 +438,55 @@ C是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pasca ... } result = 1; - goto out_buffer; + goto out_free_buffer; } ... - out_buffer: + out_free_buffer: kfree(buffer); return result; } -一个需要注意的常见错误是“一个 err 错误”,就像这样: +一个需要注意的常见错误是 ``一个 err 错误`` ,就像这样: + +.. code-block:: c err: kfree(foo->bar); kfree(foo); return ret; -这段代码的错误是,在某些退出路径上 “foo” 是 NULL。通常情况下,通过把它分离成两个 -错误标签 “err_bar:” 和 “err_foo:” 来修复这个错误。 +这段代码的错误是,在某些退出路径上 ``foo`` 是 NULL。通常情况下,通过把它分离 +成两个错误标签 ``err_free_bar:`` 和 ``err_free_foo:`` 来修复这个错误: + +.. code-block:: c + + err_free_bar: + kfree(foo->bar); + err_free_foo: + kfree(foo); + return ret; + +理想情况下,你应该模拟错误来测试所有退出路径。 - 第八章:注释 -注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的:更好 -的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。 +8) 注释 +------------------------------ -一般的,你想要你的注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把注释 -放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能需要回到 -第六章看一看。你可以做一些小注释来注明或警告某些很聪明(或者槽糕)的做法,但不要 -加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,也可以加上它做这 -些事情的原因。 +注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的: +更好的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。 -当注释内核API函数时,请使用 kernel-doc 格式。请看 -Documentation/doc-guide/和scripts/kernel-doc 以获得详细信息。 +一般的,你想要你的注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把 +注释放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能 +需要回到第六章看一看。你可以做一些小注释来注明或警告某些很聪明 (或者槽糕) 的 +做法,但不要加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么, +也可以加上它做这些事情的原因。 -Linux的注释风格是 C89 “/* ... */” 风格。不要使用 C99 风格 “// ...” 注释。 +当注释内核 API 函数时,请使用 kernel-doc 格式。请看 +Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。 -长(多行)的首选注释风格是: +长 (多行) 注释的首选风格是: + +.. code-block:: c /* * This is the preferred style for multi-line @@ -414,7 +497,9 @@ Linux的注释风格是 C89 “/* ... */” 风格。不要使用 C99 风格 “ * with beginning and ending almost-blank lines. */ -对于在 net/ 和 drivers/net/ 的文件,首选的长(多行)注释风格有些不同。 +对于在 net/ 和 drivers/net/ 的文件,首选的长 (多行) 注释风格有些不同。 + +.. code-block:: c /* The preferred comment style for files in net/ and drivers/net * looks like this. @@ -423,72 +508,77 @@ Linux的注释风格是 C89 “/* ... */” 风格。不要使用 C99 风格 “ * but there is no initial almost-blank line. */ -注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行应只 -声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据写一段 -小注释来解释它们的用途了。 - - - 第九章:你已经把事情弄糟了 - -这没什么,我们都是这样。可能你的使用了很长时间 Unix 的朋友已经告诉你 “GNU emacs” 能 -自动帮你格式化 C 源代码,而且你也注意到了,确实是这样,不过它所使用的默认值和我们 -想要的相去甚远(实际上,甚至比随机打的还要差——无数个猴子在 GNU emacs 里打字永远不 -会创造出一个好程序)(译注:请参考 Infinite Monkey Theorem) - -所以你要么放弃 GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案,你可 -以把下面这段粘贴到你的 .emacs 文件里。 - -(defun c-lineup-arglist-tabs-only (ignored) - "Line up argument lists by tabs, not spaces" - (let* ((anchor (c-langelem-pos c-syntactic-element)) - (column (c-langelem-2nd-pos c-syntactic-element)) - (offset (- (1+ column) anchor)) - (steps (floor offset c-basic-offset))) - (* (max steps 1) - c-basic-offset))) - -(add-hook 'c-mode-common-hook - (lambda () - ;; Add kernel style - (c-add-style - "linux-tabs-only" - '("linux" (c-offsets-alist - (arglist-cont-nonempty - c-lineup-gcc-asm-reg - c-lineup-arglist-tabs-only)))))) - -(add-hook 'c-mode-hook - (lambda () - (let ((filename (buffer-file-name))) - ;; Enable kernel mode for the appropriate files - (when (and filename - (string-match (expand-file-name "~/src/linux-trees") - filename)) - (setq indent-tabs-mode t) - (setq show-trailing-whitespace t) - (c-set-style "linux-tabs-only"))))) - -这会让 emacs 在 ~/src/linux-trees 目录下的 C 源文件获得更好的内核代码风格。 - -不过就算你尝试让 emacs 正确的格式化代码失败了,也并不意味着你失去了一切:还可以用 -“indent”。 - -不过,GNU indent 也有和 GNU emacs 一样有问题的设定,所以你需要给它一些命令选项。不 -过,这还不算太糟糕,因为就算是 GNU indent 的作者也认同 K&R 的权威性(GNU 的人并不是 -坏人,他们只是在这个问题上被严重的误导了),所以你只要给 indent 指定选项 “-kr -i8” -(代表 “K&R,8 个字符缩进”),或者使用 “scripts/Lindent”,这样就可以以最时髦的方式 -缩进源代码。 - -“indent” 有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册页。不过 -记住:“indent” 不能修正坏的编程习惯。 - - - 第十章:Kconfig 配置文件 - -对于遍布源码树的所有 Kconfig* 配置文件来说,它们缩进方式与 C 代码相比有所不同。紧挨 -在 “config” 定义下面的行缩进一个制表符,帮助信息则再多缩进 2 个空格。比如: - -config AUDIT +注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行 +应只声明一个数据 (不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据 +写一段小注释来解释它们的用途了。 + + +9) 你已经把事情弄糟了 +------------------------------ + +这没什么,我们都是这样。可能你的使用了很长时间 Unix 的朋友已经告诉你 +``GNU emacs`` 能自动帮你格式化 C 源代码,而且你也注意到了,确实是这样,不过它 +所使用的默认值和我们想要的相去甚远 (实际上,甚至比随机打的还要差——无数个猴子 +在 GNU emacs 里打字永远不会创造出一个好程序) (译注:Infinite Monkey Theorem) + +所以你要么放弃 GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案, +你可以把下面这段粘贴到你的 .emacs 文件里。 + +.. code-block:: none + + (defun c-lineup-arglist-tabs-only (ignored) + "Line up argument lists by tabs, not spaces" + (let* ((anchor (c-langelem-pos c-syntactic-element)) + (column (c-langelem-2nd-pos c-syntactic-element)) + (offset (- (1+ column) anchor)) + (steps (floor offset c-basic-offset))) + (* (max steps 1) + c-basic-offset))) + + (add-hook 'c-mode-common-hook + (lambda () + ;; Add kernel style + (c-add-style + "linux-tabs-only" + '("linux" (c-offsets-alist + (arglist-cont-nonempty + c-lineup-gcc-asm-reg + c-lineup-arglist-tabs-only)))))) + + (add-hook 'c-mode-hook + (lambda () + (let ((filename (buffer-file-name))) + ;; Enable kernel mode for the appropriate files + (when (and filename + (string-match (expand-file-name "~/src/linux-trees") + filename)) + (setq indent-tabs-mode t) + (setq show-trailing-whitespace t) + (c-set-style "linux-tabs-only"))))) + +这会让 emacs 在 ``~/src/linux-trees`` 下的 C 源文件获得更好的内核代码风格。 + +不过就算你尝试让 emacs 正确的格式化代码失败了,也并不意味着你失去了一切:还可 +以用 ``indent`` 。 + +不过,GNU indent 也有和 GNU emacs 一样有问题的设定,所以你需要给它一些命令选 +项。不过,这还不算太糟糕,因为就算是 GNU indent 的作者也认同 K&R 的权威性 +(GNU 的人并不是坏人,他们只是在这个问题上被严重的误导了),所以你只要给 indent +指定选项 ``-kr -i8`` (代表 ``K&R,8 字符缩进``),或使用 ``scripts/Lindent`` +这样就可以以最时髦的方式缩进源代码。 + +``indent`` 有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册。 +不过记住: ``indent`` 不能修正坏的编程习惯。 + + +10) Kconfig 配置文件 +------------------------------ + +对于遍布源码树的所有 Kconfig* 配置文件来说,它们缩进方式有所不同。紧挨着 +``config`` 定义的行,用一个制表符缩进,然而 help 信息的缩进则额外增加 2 个空 +格。举个例子:: + + config AUDIT bool "Auditing support" depends on NET help @@ -497,10 +587,10 @@ config AUDIT logging of avc messages output). Does not do system-call auditing without CONFIG_AUDITSYSCALL. -而那些危险的功能(比如某些文件系统的写支持)应该在它们的提示字符串里显著的声明这 -一点: +而那些危险的功能 (比如某些文件系统的写支持) 应该在它们的提示字符串里显著的声 +明这一点:: -config ADFS_FS_RW + config ADFS_FS_RW bool "ADFS write support (DANGEROUS)" depends on ADFS_FS ... @@ -508,34 +598,38 @@ config ADFS_FS_RW 要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.txt。 - 第十一章:数据结构 +11) 数据结构 +------------------------------ -如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引用计 |