aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Deng <theandy.deng@gmail.com>2016-05-29 11:45:10 -0400
committerJonathan Corbet <corbet@lwn.net>2016-06-03 15:35:06 -0400
commit49e48419ad0f1dd91f04bf932a4becae3cde514f (patch)
treea87ec6125687ad362e16e584b7e65f014fd311f1
parentd81749ea8b1537a382535983a269fc69c696fa0e (diff)
Documentation/zh_CN: update Chinese version CodingStyle
Chinese version CodingStyle is a little outdate, it should be updated. This patch sync with the latest CodingStyle of all changes, new chapters (chapter 19 and chapter 20) have been translated. Signed-off-by: Andy Deng <theandy.deng@gmail.com> Signed-off-by: Jonathan Corbet <corbet@lwn.net>
-rw-r--r--Documentation/zh_CN/CodingStyle581
1 files changed, 350 insertions, 231 deletions
diff --git a/Documentation/zh_CN/CodingStyle b/Documentation/zh_CN/CodingStyle
index 654afd72eb24..bbb9d6ae05ca 100644
--- a/Documentation/zh_CN/CodingStyle
+++ b/Documentation/zh_CN/CodingStyle
@@ -24,34 +24,33 @@ Documentation/CodingStyle的中文翻译
24 24
25 Linux内核代码风格 25 Linux内核代码风格
26 26
27这是一个简短的文档,描述了linux内核的首选代码风格。代码风格是因人而异的,而且我 27这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的,而且我
28不愿意把我的观点强加给任何人,不过这里所讲述的是我必须要维护的代码所遵守的风格, 28不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则那样,我也
29并且我也希望绝大多数其他代码也能遵守这个风格。请在写代码时至少考虑一下本文所述的 29希望在绝大多数事上保持这种的态度。请(在写代码时)至少考虑一下这里的代码风格。
30风格。
31 30
32首先,我建议你打印一份GNU代码规范,然后不要读。烧了它,这是一个具有重大象征性 31首先,我建议你打印一份 GNU 代码规范,然后不要读。烧了它,这是一个具有重大象征性意义
33意义的动作。 32的动作。
34 33
35不管怎样,现在我们开始: 34不管怎样,现在我们开始:
36 35
37 36
38 第一章:缩进 37 第一章:缩进
39 38
40制表符是8个字符,所以缩进也是8个字符。有些异端运动试图将缩进变为4(至2)个字符 39制表符是 8 个字符,所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4( 2
41深,这几乎相当于尝试将圆周率的值定义为3。 40个字符深,这几乎相当于尝试将圆周率的值定义为 3。
42 41
43理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的屏幕 42理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的屏幕
44连续看了20小时之后,你将会发现大一点的缩进会使你更容易分辨缩进。 43连续看了 20 小时之后,你将会发现大一点的缩进会使你更容易分辨缩进。
45 44
46现在,有些人会抱怨8个字符的缩进会使代码向右边移动的太远,在80个字符的终端屏幕上 45现在,有些人会抱怨 8 个字符的缩进会使代码向右边移动的太远,在 80 个字符的终端屏幕上
47就很难读这样的代码。这个问题的答案是,如果你需要3级以上的缩进,不管用何种方式你 46就很难读这样的代码。这个问题的答案是,如果你需要 3 级以上的缩进,不管用何种方式你
48的代码已经有问题了,应该修正你的程序。 47的代码已经有问题了,应该修正你的程序。
49 48
50简而言之,8个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太深的 49简而言之,8 个字符的缩进可以让代码更容易阅读,还有一个好处是当你的函数嵌套太深的
51时候可以给你警告。留心这个警告。 50时候可以给你警告。留心这个警告。
52 51
53在switch语句中消除多级缩进的首选的方式是让“switch”和从属于它的“case”标签对齐于同 52 switch 语句中消除多级缩进的首选的方式是让 “switch” 和从属于它的 “case” 标签
54一列,而不要“两次缩进”“case”标签。比如: 53对齐列,而不要 “两次缩进” “case” 标签。比如:
55 54
56 switch (suffix) { 55 switch (suffix) {
57 case 'G': 56 case 'G':
@@ -70,7 +69,6 @@ Documentation/CodingStyle的中文翻译
70 break; 69 break;
71 } 70 }
72 71
73
74不要把多个语句放在一行里,除非你有什么东西要隐藏: 72不要把多个语句放在一行里,除非你有什么东西要隐藏:
75 73
76 if (condition) do_this; 74 if (condition) do_this;
@@ -79,7 +77,7 @@ Documentation/CodingStyle的中文翻译
79也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读的表 77也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读的表
80达式。 78达式。
81 79
82除了注释、文档和Kconfig之外,不要使用空格来缩进,前面的例子是例外,是有意为之。 80除了注释、文档和 Kconfig 之外,不要使用空格来缩进,前面的例子是例外,是有意为之。
83 81
84选用一个好的编辑器,不要在行尾留空格。 82选用一个好的编辑器,不要在行尾留空格。
85 83
@@ -88,27 +86,18 @@ Documentation/CodingStyle的中文翻译
88 86
89代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。 87代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
90 88
91每一行的长度的限制是80列,我们强烈建议您遵守这个惯例。 89每一行的长度的限制是 80 列,我们强烈建议您遵守这个惯例。
92 90
93长于80列的语句要打散成有意义的片段。每个片段要明显短于原来的语句,而且放置的位置 91长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性,并且不会隐藏
94也明显的靠右。同样的规则也适用于有很长参数列表的函数头。长字符串也要打散成较短的 92信息。子片段要明显短于母片段,并明显靠右。这同样适用于有着很长参数列表的函数头。
95字符串。唯一的例外是超过80列可以大幅度提高可读性并且不会隐藏信息的情况。 93然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这将导致无法 grep 这些
96 94信息。
97void fun(int a, int b, int c)
98{
99 if (condition)
100 printk(KERN_WARNING "Warning this is a long printk with "
101 "3 parameters a: %u b: %u "
102 "c: %u \n", a, b, c);
103 else
104 next_statement;
105}
106 95
107 第三章:大括号和空格的放置 96 第三章:大括号和空格的放置
108 97
109C语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放置策 98C语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放置策
110略并没有多少技术上的原因,不过首选的方式,就像Kernighan和Ritchie展示给我们的, 99略并没有多少技术上的原因,不过首选的方式,就像 Kernighan Ritchie 展示给我们的,
111把起始大括号放在行尾,而把结束大括号放在行首,所以: 100起始大括号放在行尾,而把结束大括号放在行首,所以:
112 101
113 if (x is true) { 102 if (x is true) {
114 we do y 103 we do y
@@ -134,12 +123,12 @@ C语言风格中另外一个常见问题是大括号的放置。和缩进大小
134 body of function 123 body of function
135 } 124 }
136 125
137全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过所有思维健全的人都知道 126全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过所有思维健全的人都知道
138aK&R是_正确的_,并且bK&R是正确的。此外,不管怎样函数都是特殊的(C语言中 127(a) K&R _正确的_,并且 (b) K&R 是正确的。此外,不管怎样函数都是特殊的(C
139函数是不能嵌套的)。 128函数是不能嵌套的)。
140 129
141注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是do语句中的 130注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是 do 语句中的
142“while”或者if语句中的“else”,像这样: 131“while” 或者 if 语句中的 “else”,像这样:
143 132
144 do { 133 do {
145 body of do-loop 134 body of do-loop
@@ -158,41 +147,50 @@ a)K&R是_正确的_,并且(b)K&R是正确的。此外,不管怎样函
158理由:K&R。 147理由:K&R。
159 148
160也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可 149也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可
161读性。因此,由于你的屏幕上的新行是不可再生资源(想想25行的终端屏幕),你将会有更 150读性。因此,由于你的屏幕上的新行是不可再生资源(想想 25 行的终端屏幕),你将会有更
162多的空行来放置注释。 151多的空行来放置注释。
163 152
164当只有一个单独的语句的时候,不用加不必要的大括号。 153当只有一个单独的语句的时候,不用加不必要的大括号。
165 154
166if (condition) 155 if (condition)
167 action(); 156 action();
157
158
159
160 if (condition)
161 do_this();
162 else
163 do_that();
168 164
169这点不适用于本身为某个条件语句的一个分支的单独语句。这时需要在两个分支里都使用大 165这并不适用于只有一个条件分支是单语句的情况;这时所有分支都要使用大括号:
170括号。
171 166
172if (condition) { 167 if (condition) {
173 do_this(); 168 do_this();
174 do_that(); 169 do_that();
175} else { 170 } else {
176 otherwise(); 171 otherwise();
177} 172 }
178 173
179 3.1:空格 174 3.1:空格
180 175
181Linux内核的空格使用方式(主要)取决于它是用于函数还是关键字。(大多数)关键字后 176Linux 内核的空格使用方式(主要)取决于它是用于函数还是关键字。(大多数)关键字后
182要加一个空格。值得注意的例外是sizeof、typeof、alignof和__attribute__,这些关键字 177要加一个空格。值得注意的例外是 sizeof、typeof、alignof __attribute__,这些
183某些程度上看起来更像函数(它们在Linux里也常常伴随小括号而使用,尽管在C语言这样 178关键字某些程度上看起来更像函数(它们在 Linux 里也常常伴随小括号而使用,尽管在 C
184的小括号不是必需的,就像“struct fileinfo info”声明过后的“sizeof info”)。 179这样的小括号不是必需的,就像 “struct fileinfo info” 声明过后的 “sizeof info”)。
185 180
186所以在这些关键字之后放一个空格: 181所以在这些关键字之后放一个空格:
182
187 if, switch, case, for, do, while 183 if, switch, case, for, do, while
188但是不要在sizeof、typeof、alignof或者__attribute__这些关键字之后放空格。例如, 184
185但是不要在 sizeof、typeof、alignof 或者 __attribute__ 这些关键字之后放空格。例如,
186
189 s = sizeof(struct file); 187 s = sizeof(struct file);
190 188
191不要在小括号里的表达式两侧加空格。这是一个反例: 189不要在小括号里的表达式两侧加空格。这是一个反例:
192 190
193 s = sizeof( struct file ); 191 s = sizeof( struct file );
194 192
195当声明指针类型或者返回指针类型的函数时,“*”的首选使用方式是使之靠近变量名或者函 193当声明指针类型或者返回指针类型的函数时,“*” 的首选使用方式是使之靠近变量名或者函
196数名,而不是靠近类型名。例子: 194数名,而不是靠近类型名。例子:
197 195
198 char *linux_banner; 196 char *linux_banner;
@@ -204,15 +202,18 @@ Linux内核的空格使用方式(主要)取决于它是用于函数还是关
204 = + - < > * / % | & ^ <= >= == != ? : 202 = + - < > * / % | & ^ <= >= == != ? :
205 203
206但是一元操作符后不要加空格: 204但是一元操作符后不要加空格:
205
207 & * + - ~ ! sizeof typeof alignof __attribute__ defined 206 & * + - ~ ! sizeof typeof alignof __attribute__ defined
208 207
209后缀自加和自减一元操作符前不加空格: 208后缀自加和自减一元操作符前不加空格:
209
210 ++ -- 210 ++ --
211 211
212前缀自加和自减一元操作符后不加空格: 212前缀自加和自减一元操作符后不加空格:
213
213 ++ -- 214 ++ --
214 215
215.和“->”结构体成员操作符前后不加空格。 216. “->” 结构体成员操作符前后不加空格。
216 217
217不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你 218不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你
218就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器就不 219就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器就不
@@ -225,23 +226,23 @@ Linux内核的空格使用方式(主要)取决于它是用于函数还是关
225 226
226 第四章:命名 227 第四章:命名
227 228
228C是一个简朴的语言,你的命名也应该这样。和Modula-2和Pascal程序员不同,C程序员不使 229C是一个简朴的语言,你的命名也应该这样。和 Modula-2 Pascal 程序员不同,C 程序员
229用类似ThisVariableIsATemporaryCounter这样华丽的名字。C程序员会称那个变量为“tmp” 230不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会称那个变量
230,这样写起来会更容易,而且至少不会令其难于理解。 231为 “tmp”,这样写起来会更容易,而且至少不会令其难于理解。
231 232
232不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的名字 233不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的名字
233。称一个全局函数为“foo”是一个难以饶恕的错误。 234。称一个全局函数为 “foo” 是一个难以饶恕的错误。
234 235
235全局变量(只有当你真正需要它们的时候再用它)需要有一个具描述性的名字,就像全局函 236全局变量(只有当你真正需要它们的时候再用它)需要有一个具描述性的名字,就像全局函
236数。如果你有一个可以计算活动用户数量的函数,你应该叫它“count_active_users()”或者 237数。如果你有一个可以计算活动用户数量的函数,你应该叫它 “count_active_users()”
237类似的名字,你不应该叫它“cntuser()”。 238或者类似的名字,你不应该叫它 “cntuser()”。
238 239
239在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型而 240在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型而
240且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题的程序。 241且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题的程序。
241 242
242本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计数器 243本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计数器
243,它应该被称为“i”。叫它“loop_counter”并无益处,如果它没有被误解的可能的话。类似 244,它应该被称为 “i”。叫它 “loop_counter” 并无益处,如果它没有被误解的可能的话。
244的,“tmp”可以用来称呼任意类型的临时变量。 245,“tmp” 可以用来称呼任意类型的临时变量。
245 246
246如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综合症 247如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综合症
247。请看第六章(函数)。 248。请看第六章(函数)。
@@ -249,9 +250,9 @@ C是一个简朴的语言,你的命名也应该这样。和Modula-2和Pascal
249 250
250 第五章:Typedef 251 第五章:Typedef
251 252
252不要使用类似“vps_t”之类的东西。 253不要使用类似 “vps_t” 之类的东西。
253 254
254对结构体和指针使用typedef是一个错误。当你在代码里看到: 255对结构体和指针使用 typedef 是一个错误。当你在代码里看到:
255 256
256 vps_t a; 257 vps_t a;
257 258
@@ -261,91 +262,91 @@ C是一个简朴的语言,你的命名也应该这样。和Modula-2和Pascal
261 262
262 struct virtual_container *a; 263 struct virtual_container *a;
263 264
264你就知道“a”是什么了。 265你就知道 “a” 是什么了。
265 266
266很多人认为typedef“能提高可读性”。实际不是这样的。它们只在下列情况下有用: 267很多人认为 typedef “能提高可读性”。实际不是这样的。它们只在下列情况下有用:
267 268
268 (a) 完全不透明的对象(这种情况下要主动使用typedef来隐藏这个对象实际上是什么)。 269 (a) 完全不透明的对象(这种情况下要主动使用 typedef 来隐藏这个对象实际上是什么)。
269 270
270 例如:“pte_t”等不透明对象,你只能用合适的访问函数来访问它们。 271 例如:“pte_t” 等不透明对象,你只能用合适的访问函数来访问它们。
271 272
272 注意!不透明性和“访问函数”本身是不好的。我们使用pte_t等类型的原因在于真的是 273 注意!不透明性和“访问函数”本身是不好的。我们使用 pte_t 等类型的原因在于真的是
273 完全没有任何共用的可访问信息。 274 完全没有任何共用的可访问信息。
274 275
275 (b) 清楚的整数类型,如此,这层抽象就可以帮助消除到底是“int”还是“long”的混淆。 276 (b) 清楚的整数类型,如此,这层抽象就可以帮助消除到底是 “int” 还是 “long” 的混淆。
276 277
277 u8/u16/u32是完全没有问题的typedef,不过它们更符合类别(d)而不是这里。 278 u8/u16/u32 是完全没有问题的 typedef,不过它们更符合类别 (d) 而不是这里。
278 279
279 再次注意!要这样做,必须事出有因。如果某个变量是“unsigned long“,那么没有必要 280 再次注意!要这样做,必须事出有因。如果某个变量是 “unsigned long“,那么没有必要
280 281
281 typedef unsigned long myflags_t; 282 typedef unsigned long myflags_t;
282 283
283 不过如果有一个明确的原因,比如它在某种情况下可能会是一个“unsigned int”而在 284 不过如果有一个明确的原因,比如它在某种情况下可能会是一个 “unsigned int” 而在
284 其他情况下可能为“unsigned long”,那么就不要犹豫,请务必使用typedef。 285 其他情况下可能为 “unsigned long”,那么就不要犹豫,请务必使用 typedef。
285 286
286 (c) 当你使用sparse按字面的创建一个新类型来做类型检查的时候。 287 (c) 当你使用sparse按字面的创建一个新类型来做类型检查的时候。
287 288
288 (d) 和标准C99类型相同的类型,在某些例外的情况下。 289 (d) 和标准C99类型相同的类型,在某些例外的情况下。
289 290
290 虽然让眼睛和脑筋来适应新的标准类型比如“uint32_t”不需要花很多时间,可是有些 291 虽然让眼睛和脑筋来适应新的标准类型比如 “uint32_t” 不需要花很多时间,可是有些
291 人仍然拒绝使用它们。 292 人仍然拒绝使用它们。
292 293
293 因此,Linux特有的等同于标准类型的“u8/u16/u32/u64”类型和它们的有符号类型是被 294 因此,Linux 特有的等同于标准类型的 “u8/u16/u32/u64” 类型和它们的有符号类型是被
294 允许的——尽管在你自己的新代码中,它们不是强制要求要使用的。 295 允许的——尽管在你自己的新代码中,它们不是强制要求要使用的。
295 296
296 当编辑已经使用了某个类型集的已有代码时,你应该遵循那些代码中已经做出的选择。 297 当编辑已经使用了某个类型集的已有代码时,你应该遵循那些代码中已经做出的选择。
297 298
298 (e) 可以在用户空间安全使用的类型。 299 (e) 可以在用户空间安全使用的类型。
299 300
300 在某些用户空间可见的结构体里,我们不能要求C99类型而且不能用上面提到的“u32” 301 在某些用户空间可见的结构体里,我们不能要求C99类型而且不能用上面提到的 “u32”
301 类型。因此,我们在与用户空间共享的所有结构体中使用__u32和类似的类型。 302 类型。因此,我们在与用户空间共享的所有结构体中使用 __u32 和类似的类型。
302 303
303可能还有其他的情况,不过基本的规则是永远不要使用typedef,除非你可以明确的应用上 304可能还有其他的情况,不过基本的规则是永远不要使用 typedef,除非你可以明确的应用上
304述某个规则中的一个。 305述某个规则中的一个。
305 306
306总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们就不 307总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们就不
307应该是一个typedef。 308应该是一个 typedef。
308 309
309 310
310 第六章:函数 311 第六章:函数
311 312
312函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完(我们都知 313函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完(我们都知
313道ISO/ANSI屏幕大小是80x24),只做一件事情,而且把它做好。 314 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好。
314 315
315一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理论上 316一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理论上
316很简单的只有一个很长(但是简单)的case语句的函数,而且你需要在每个case里做很多很 317很简单的只有一个很长(但是简单)的 case 语句的函数,而且你需要在每个 case 里做
317小的事情,这样的函数尽管很长,但也是可以的。 318多很的事情,这样的函数尽管很长,但也是可以的。
318 319
319不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能甚至 320不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能甚至
320搞不清楚这个函数的目的,你应该严格的遵守前面提到的长度限制。使用辅助函数,并为之 321搞不清楚这个函数的目的,你应该严格的遵守前面提到的长度限制。使用辅助函数,并为之
321取个具描述性的名字(如果你觉得它们的性能很重要的话,可以让编译器内联它们,这样的 322取个具描述性的名字(如果你觉得它们的性能很重要的话,可以让编译器内联它们,这样的
322效果往往会比你写一个复杂函数的效果要好。) 323效果往往会比你写一个复杂函数的效果要好。)
323 324
324函数的另外一个衡量标准是本地变量的数量。此数量不应超过5-10个,否则你的函数就有 325函数的另外一个衡量标准是本地变量的数量。此数量不应超过 5-10 个,否则你的函数就有
325问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松的同时跟 326问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松的同时跟
326踪7个不同的事物,如果再增多的话,就会糊涂了。即便你聪颖过人,你也可能会记不清你2 327 7 个不同的事物,如果再增多的话,就会糊涂了。即便你聪颖过人,你也可能会记不清你
327个星期前做过的事情。 3282 个星期前做过的事情。
328 329
329在源文件里,使用空行隔开不同的函数。如果该函数需要被导出,它的EXPORT*宏应该紧贴 330在源文件里,使用空行隔开不同的函数。如果该函数需要被导出,它的 EXPORT* 宏应该紧贴
330在它的结束大括号之下。比如: 331在它的结束大括号之下。比如:
331 332
332int system_is_up(void) 333 int system_is_up(void)
333{ 334 {
334 return system_state == SYSTEM_RUNNING; 335 return system_state == SYSTEM_RUNNING;
335} 336 }
336EXPORT_SYMBOL(system_is_up); 337 EXPORT_SYMBOL(system_is_up);
337 338
338在函数原型中,包含函数名和它们的数据类型。虽然C语言里没有这样的要求,在Linux里这 339在函数原型中,包含函数名和它们的数据类型。虽然C语言里没有这样的要求,在 Linux 里这
339是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。 340是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
340 341
341 342
342 第七章:集中的函数退出途径 343 第七章:集中的函数退出途径
343 344
344虽然被某些人声称已经过时,但是goto语句的等价物还是经常被编译器所使用,具体形式是 345虽然被某些人声称已经过时,但是 goto 语句的等价物还是经常被编译器所使用,具体形式是
345无条件跳转指令。 346无条件跳转指令。
346 347
347当一个函数从多个位置退出并且需要做一些清理,goto 348当一个函数从多个位置退出并且需要做一些清理见操作时,goto
348 349如果并需要清操作,那么直接 return 即可
349 350
350理由是: 351理由是:
351 352
@@ -354,26 +355,37 @@ EXPORT_SYMBOL(system_is_up);
354- 可以避免由于修改时忘记更新某个单独的退出点而导致的错误 355- 可以避免由于修改时忘记更新某个单独的退出点而导致的错误
355- 减轻了编译器的工作,无需删除冗余代码;) 356- 减轻了编译器的工作,无需删除冗余代码;)
356 357
357int fun(int a) 358 int fun(int a)
358{ 359 {
359 int result = 0; 360 int result = 0;
360 char *buffer = kmalloc(SIZE); 361 char *buffer;
361 362
362 if (buffer == NULL) 363 buffer = kmalloc(SIZE, GFP_KERNEL);
363 return -ENOMEM; 364 if (!buffer)
364 365 return -ENOMEM;
365 if (condition1) { 366
366 while (loop1) { 367 if (condition1) {
367 ... 368 while (loop1) {
369 ...
370 }
371 result = 1;
372 goto out_buffer;
368 } 373 }
369 result = 1; 374 ...
370 goto out; 375 out_buffer:
376 kfree(buffer);
377 return result;
371 } 378 }
372 ... 379
373out: 380一个需要注意的常见错误是“一个 err 错误”,就像这样:
374 kfree(buffer); 381
375 return result; 382 err:
376} 383 kfree(foo->bar);
384 kfree(foo);
385 return ret;
386
387这段代码的错误是,在某些退出路径上 “foo” 是 NULL。通常情况下,通过把它分离成两个
388错误标签 “err_bar:” 和 “err_foo:” 来修复这个错误。
377 389
378 第八章:注释 390 第八章:注释
379 391
@@ -386,10 +398,10 @@ out:
386加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,也可以加上它做这 398加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,也可以加上它做这
387些事情的原因。 399些事情的原因。
388 400
389当注释内核API函数时,请使用kernel-doc格式。请看 401当注释内核API函数时,请使用 kernel-doc 格式。请看
390Documentation/kernel-doc-nano-HOWTO.txt和scripts/kernel-doc以获得详细信息。 402Documentation/kernel-doc-nano-HOWTO.txt和scripts/kernel-doc 以获得详细信息。
391 403
392Linux的注释风格是C89“/* ... */”风格。不要使用C99风格“// ...”注释。 404Linux的注释风格是 C89 “/* ... */” 风格。不要使用 C99 风格 “// ...” 注释。
393 405
394长(多行)的首选注释风格是: 406长(多行)的首选注释风格是:
395 407
@@ -402,6 +414,15 @@ Linux的注释风格是C89“/* ... */”风格。不要使用C99风格“// ...
402 * with beginning and ending almost-blank lines. 414 * with beginning and ending almost-blank lines.
403 */ 415 */
404 416
417对于在 net/ 和 drivers/net/ 的文件,首选的长(多行)注释风格有些不同。
418
419 /* The preferred comment style for files in net/ and drivers/net
420 * looks like this.
421 *
422 * It is nearly the same as the generally preferred comment style,
423 * but there is no initial almost-blank line.
424 */
425
405注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行应只 426注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行应只
406声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据写一段 427声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据写一段
407小注释来解释它们的用途了。 428小注释来解释它们的用途了。
@@ -409,49 +430,63 @@ Linux的注释风格是C89“/* ... */”风格。不要使用C99风格“// ...
409 430
410 第九章:你已经把事情弄糟了 431 第九章:你已经把事情弄糟了
411 432
412这没什么,我们都是这样。可能你的使用了很长时间Unix的朋友已经告诉你“GNU emacs”能 433这没什么,我们都是这样。可能你的使用了很长时间 Unix 的朋友已经告诉你 “GNU emacs” 能
413自动帮你格式化C源代码,而且你也注意到了,确实是这样,不过它所使用的默认值和我们 434自动帮你格式化 C 源代码,而且你也注意到了,确实是这样,不过它所使用的默认值和我们
414想要的相去甚远(实际上,甚至比随机打的还要差——无数个猴子在GNU emacs里打字永远不 435想要的相去甚远(实际上,甚至比随机打的还要差——无数个猴子在 GNU emacs 里打字永远不
415会创造出一个好程序)(译注:请参考Infinite Monkey Theorem) 436会创造出一个好程序)(译注:请参考 Infinite Monkey Theorem)
416 437
417所以你要么放弃GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案,你可 438所以你要么放弃 GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案,你可
418以把下面这段粘贴到你的.emacs文件里。 439以把下面这段粘贴到你的 .emacs 文件里。
419 440
420(defun linux-c-mode () 441(defun c-lineup-arglist-tabs-only (ignored)
421 "C mode with adjusted defaults for use with the Linux kernel." 442 "Line up argument lists by tabs, not spaces"
422 (interactive) 443 (let* ((anchor (c-langelem-pos c-syntactic-element))
423 (c-mode) 444 (column (c-langelem-2nd-pos c-syntactic-element))
424 (c-set-style "K&R") 445 (offset (- (1+ column) anchor))
425 (setq tab-width 8) 446 (steps (floor offset c-basic-offset)))
426 (setq indent-tabs-mode t) 447 (* (max steps 1)
427 (setq c-basic-offset 8)) 448 c-basic-offset)))
428 449
429这样就定义了M-x linux-c-mode命令。当你hack一个模块的时候,如果你把字符串 450(add-hook 'c-mode-common-hook
430-*- linux-c -*-放在头两行的某个位置,这个模式将会被自动调用。如果你希望在你修改 451 (lambda ()
431/usr/src/linux里的文件时魔术般自动打开linux-c-mode的话,你也可能需要添加 452 ;; Add kernel style
432 453 (c-add-style
433(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode) 454 "linux-tabs-only"
434 auto-mode-alist)) 455 '("linux" (c-offsets-alist
435 456 (arglist-cont-nonempty
436到你的.emacs文件里。 457 c-lineup-gcc-asm-reg
437 458 c-lineup-arglist-tabs-only))))))
438不过就算你尝试让emacs正确的格式化代码失败了,也并不意味着你失去了一切:还可以用“ 459
439indent”。 460(add-hook 'c-mode-hook
440 461 (lambda ()
441不过,GNU indent也有和GNU emacs一样有问题的设定,所以你需要给它一些命令选项。不 462 (let ((filename (buffer-file-name)))
442过,这还不算太糟糕,因为就算是GNU indent的作者也认同K&R的权威性(GNU的人并不是坏 463 ;; Enable kernel mode for the appropriate files
443人,他们只是在这个问题上被严重的误导了),所以你只要给indent指定选项“-kr -i8” 464 (when (and filename
444(代表“K&R,8个字符缩进”),或者使用“scripts/Lindent”,这样就可以以最时髦的方式 465 (string-match (expand-file-name "~/src/linux-trees")
466 filename))
467 (setq indent-tabs-mode t)
468 (setq show-trailing-whitespace t)
469 (c-set-style "linux-tabs-only")))))
470
471这会让 emacs 在 ~/src/linux-trees 目录下的 C 源文件获得更好的内核代码风格。
472
473不过就算你尝试让 emacs 正确的格式化代码失败了,也并不意味着你失去了一切:还可以用
474“indent”。
475
476不过,GNU indent 也有和 GNU emacs 一样有问题的设定,所以你需要给它一些命令选项。不
477过,这还不算太糟糕,因为就算是 GNU indent 的作者也认同 K&R 的权威性(GNU 的人并不是
478坏人,他们只是在这个问题上被严重的误导了),所以你只要给 indent 指定选项 “-kr -i8”
479(代表 “K&R,8 个字符缩进”),或者使用 “scripts/Lindent”,这样就可以以最时髦的方式
445缩进源代码。 480缩进源代码。
446 481
447“indent”有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册页。不过 482“indent” 有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册页。不过
448记住:“indent”不能修正坏的编程习惯。 483记住:“indent” 不能修正坏的编程习惯。
449 484
450 485
451 第十章:Kconfig配置文件 486 第十章:Kconfig 配置文件
452 487
453对于遍布源码树的所有Kconfig*配置文件来说,它们缩进方式与C代码相比有所不同。紧挨 488对于遍布源码树的所有 Kconfig* 配置文件来说,它们缩进方式与 C 代码相比有所不同。紧挨
454在“config”定义下面的行缩进一个制表符,帮助信息则再多缩进2个空格。比如: 489 “config” 定义下面的行缩进一个制表符,帮助信息则再多缩进 2 个空格。比如:
455 490
456config AUDIT 491config AUDIT
457 bool "Auditing support" 492 bool "Auditing support"
@@ -470,7 +505,7 @@ config ADFS_FS_RW
470 depends on ADFS_FS 505 depends on ADFS_FS
471 ... 506 ...
472 507
473要查看配置文件的完整文档,请看Documentation/kbuild/kconfig-language.txt。 508要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.txt。
474 509
475 510
476 第十一章:数据结构 511 第十一章:数据结构
@@ -489,11 +524,11 @@ config ADFS_FS_RW
489很多数据结构实际上有2级引用计数,它们通常有不同“类”的用户。子类计数器统计子类用 524很多数据结构实际上有2级引用计数,它们通常有不同“类”的用户。子类计数器统计子类用
490户的数量,每当子类计数器减至零时,全局计数器减一。 525户的数量,每当子类计数器减至零时,全局计数器减一。
491 526
492这种“多级引用计数”的例子可以在内存管理(“struct mm_struct”:mm_users和mm_count) 527这种“多级引用计数”的例子可以在内存管理(“struct mm_struct”:mm_users mm_count)
493和文件系统(“struct super_block”:s_count和s_active)中找到。 528和文件系统(“struct super_block”:s_count和s_active)中找到。
494 529
495记住:如果另一个执行线索可以找到你的数据结构,但是这个数据结构没有引用计数器,这 530记住:如果另一个执行线索可以找到你的数据结构,但是这个数据结构没有引用计数器,这
496里几乎肯定是一个bug。 531里几乎肯定是一个 bug。
497 532
498 533
499 第十二章:宏,枚举和RTL 534 第十二章:宏,枚举和RTL
@@ -508,102 +543,128 @@ config ADFS_FS_RW
508 543
509一般的,如果能写成内联函数就不要写成像函数的宏。 544一般的,如果能写成内联函数就不要写成像函数的宏。
510 545
511含有多个语句的宏应该被包含在一个do-while代码块里: 546含有多个语句的宏应该被包含在一个 do-while 代码块里:
512 547
513#define macrofun(a, b, c) \ 548 #define macrofun(a, b, c) \
514 do { \ 549 do { \
515 if (a == 5) \ 550 if (a == 5) \
516 do_this(b, c); \ 551 do_this(b, c); \
517 } while (0) 552 } while (0)
518 553
519使用宏的时候应避免的事情: 554使用宏的时候应避免的事情:
520 555
5211) 影响控制流程的宏: 5561) 影响控制流程的宏:
522 557
523#define FOO(x) \ 558 #define FOO(x) \
524 do { \ 559 do { \
525 if (blah(x) < 0) \ 560 if (blah(x) < 0) \
526 return -EBUGGERED; \ 561 return -EBUGGERED; \
527 } while(0) 562 } while (0)
528 563
529非常不好。它看起来像一个函数,不过却能导致“调用”它的函数退出;不要打乱读者大脑里 564非常不好。它看起来像一个函数,不过却能导致“调用”它的函数退出;不要打乱读者大脑里
530的语法分析器。 565的语法分析器。
531 566
5322) 依赖于一个固定名字的本地变量的宏: 5672) 依赖于一个固定名字的本地变量的宏:
533 568
534#define FOO(val) bar(index, val) 569 #define FOO(val) bar(index, val)
535 570
536可能看起来像是个不错的东西,不过它非常容易把读代码的人搞糊涂,而且容易导致看起来 571可能看起来像是个不错的东西,不过它非常容易把读代码的人搞糊涂,而且容易导致看起来
537不相关的改动带来错误。 572不相关的改动带来错误。
538 573
5393) 作为左值的带参数的宏: FOO(x) = y;如果有人把FOO变成一个内联函数的话,这种用 5743) 作为左值的带参数的宏: FOO(x) = y;如果有人把 FOO 变成一个内联函数的话,这种用
540法就会出错了。 575法就会出错了。
541 576
5424) 忘记了优先级:使用表达式定义常量的宏必须将表达式置于一对小括号之内。带参数的 5774) 忘记了优先级:使用表达式定义常量的宏必须将表达式置于一对小括号之内。带参数的
543宏也要注意此类问题。 578宏也要注意此类问题。
544 579
545#define CONSTANT 0x4000 580 #define CONSTANT 0x4000
546#define CONSTEXP (CONSTANT | 3) 581 #define CONSTEXP (CONSTANT | 3)
582
5835) 在宏里定义类似函数的本地变量时命名冲突:
547 584
548cpp手册对宏的讲解很详细。Gcc internals手册也详细讲解了RTL(译注:register 585 #define FOO(x) \
586 ({ \
587 typeof(x) ret; \
588 ret = calc_ret(x); \
589 (ret); \
590 })
591
592ret 是本地变量的通用名字 - __foo_ret 更不容易与一个已存在的变量冲突。
593
594cpp 手册对宏的讲解很详细。gcc internals 手册也详细讲解了 RTL(译注:register
549transfer language),内核里的汇编语言经常用到它。 595transfer language),内核里的汇编语言经常用到它。
550 596
551 597
552 第十三章:打印内核消息 598 第十三章:打印内核消息
553 599
554内核开发者应该是受过良好教育的。请一定注意内核信息的拼写,以给人以好的印象。不要 600内核开发者应该是受过良好教育的。请一定注意内核信息的拼写,以给人以好的印象。不要
555用不规范的单词比如“dont”,而要用“do not”或者“don't”。保证这些信息简单、明了、 601用不规范的单词比如 “dont”,而要用 “do not”或者 “don't”。保证这些信息简单、明了、
556歧义。 602义。
557 603
558内核信息不必以句号(译注:英文句号,即点)结束。 604内核信息不必以句号(译注:英文句号,即点)结束。
559 605
560在小括号里打印数字(%d)没有任何价值,应该避免这样做。 606在小括号里打印数字 (%d) 没有任何价值,应该避免这样做。
561 607
562<linux/device.h>里有一些驱动模型诊断宏,你应该使用它们,以确保信息对应于正确的 608<linux/device.h> 里有一些驱动模型诊断宏,你应该使用它们,以确保信息对应于正确的
563设备和驱动,并且被标记了正确的消息级别。这些宏有:dev_err(), dev_warn(), 609设备和驱动,并且被标记了正确的消息级别。这些宏有:dev_err()dev_warn()
564dev_info()等等。对于那些不和某个特定设备相关连的信息,<linux/kernel.h>定义了 610dev_info() 等等。对于那些不和某个特定设备相关连的信息,<linux/printk.h> 定义了
565pr_debug()pr_info()。 611pr_notice()pr_info(),pr_warn(),pr_err() 和其他
566 612
567写出好的调试信息可以是一个很大的挑战;当你写出来之后,这些信息在远程除错的时候 613写出好的调试信息可以是一个很大的挑战;一旦你写出后,这些信息在远程除错时能提供极大
568就会成为极大的帮助。当DEBUG符号没有被定义的时候,这些信息不应该被编译进内核里 614的帮助。然而打印调试信息的处理方式同打印非调试信息不同。其他 pr_XXX() 函数能无条件地
569(也就是说,默认地,它们不应该被包含在内)。如果你使用dev_dbg()或者pr_debug(), 615打印,pr_debug() 却不;默认情况下它不会被编译,除非定义了 DEBUG 或设定了
570就能自动达到这个效果。很多子系统拥有Kconfig选项来启用-DDEBUG。还有一个相关的惯例 616CONFIG_DYNAMIC_DEBUG。实际这同样是为了 dev_dbg(),一个相关约定是在一个已经开启了
571是使用VERBOSE_DEBUG来添加dev_vdbg()消息到那些已经由DEBUG启用的消息之上。 617DEBUG 时,使用 VERBOSE_DEBUG 来添加 dev_vdbg()。
618
619许多子系统拥有 Kconfig 调试选项来开启 -DDEBUG 在对应的 Makefile 里面;在其他
620情况下,特殊文件使用 #define DEBUG。当一条调试信息需要被无条件打印时,例如,如果
621已经包含一个调试相关的 #ifdef 条件,printk(KERN_DEBUG ...) 就可被使用。
572 622
573 623
574 第十四章:分配内存 624 第十四章:分配内存
575 625
576内核提供了下面的一般用途的内存分配函数:kmalloc(),kzalloc(),kcalloc()和 626内核提供了下面的一般用途的内存分配函数:
577vmalloc()。请参考API文档以获取有关它们的详细信息。 627kmalloc(),kzalloc(),kmalloc_array(),kcalloc(),vmalloc() 和 vzalloc()。
628请参考 API 文档以获取有关它们的详细信息。
578 629
579传递结构体大小的首选形式是这样的: 630传递结构体大小的首选形式是这样的:
580 631
581 p = kmalloc(sizeof(*p), ...); 632 p = kmalloc(sizeof(*p), ...);
582 633
583另外一种传递方式中,sizeof的操作数是结构体的名字,这样会降低可读性,并且可能会引 634另外一种传递方式中,sizeof 的操作数是结构体的名字,这样会降低可读性,并且可能会引
584入bug。有可能指针变量类型被改变时,而对应的传递给内存分配函数的sizeof的结果不变。 635 bug。有可能指针变量类型被改变时,而对应的传递给内存分配函数的 sizeof 的结果不变。
585 636
586强制转换一个void指针返回值是多余的。C语言本身保证了从void指针到其他任何指针类型 637强制转换一个 void 指针返回值是多余的。C 语言本身保证了从 void 指针到其他任何指针类型
587的转换是没有问题的。 638的转换是没有问题的。
588 639
640分配一个数组的首选形式是这样的:
641
642 p = kmalloc_array(n, sizeof(...), ...);
643
644分配一个零长数组的首选形式是这样的:
645
646 p = kcalloc(n, sizeof(...), ...);
647
648两种形式检查分配大小 n * sizeof(...) 的溢出,如果溢出返回 NULL。
649
589 650
590 第十五章:内联弊病 651 第十五章:内联弊病
591 652
592有一个常见的误解是内联函数是gcc提供的可以让代码运行更快的一个选项。虽然使用内联 653有一个常见的误解是内联函数是 gcc 提供的可以让代码运行更快的一个选项。虽然使用内联
593函数有时候是恰当的(比如作为一种替代宏的方式,请看第十二章),不过很多情况下不是 654函数有时候是恰当的(比如作为一种替代宏的方式,请看第十二章),不过很多情况下不是
594这样。inline关键字的过度使用会使内核变大,从而使整个系统运行速度变慢。因为大内核 655这样。inline 关键字的过度使用会使内核变大,从而使整个系统运行速度变慢。因为大内核
595会占用更多的指令高速缓存(译注:一级缓存通常是指令缓存和数据缓存分开的)而且会导 656会占用更多的指令高速缓存(译注:一级缓存通常是指令缓存和数据缓存分开的)而且会导
596致pagecache的可用内存减少。想象一下,一次pagecache未命中就会导致一次磁盘寻址, 657 pagecache 的可用内存减少。想象一下,一次pagecache未命中就会导致一次磁盘寻址,
597耗时5毫秒。5毫秒的时间内CPU能执行很多很多指令。 658耗时 5 毫秒。5 毫秒的时间内 CPU 能执行很多很多指令。
598 659
599一个基本的原则是如果一个函数有3行以上,就不要把它变成内联函数。这个原则的一个例 660一个基本的原则是如果一个函数有 3 行以上,就不要把它变成内联函数。这个原则的一个例
600外是,如果你知道某个参数是一个编译时常量,而且因为这个常量你确定编译器在编译时能 661外是,如果你知道某个参数是一个编译时常量,而且因为这个常量你确定编译器在编译时能
601优化掉你的函数的大部分代码,那仍然可以给它加上inline关键字。kmalloc()内联函数就 662优化掉你的函数的大部分代码,那仍然可以给它加上 inline 关键字。kmalloc() 内联函数就
602是一个很好的例子。 663是一个很好的例子。
603 664
604人们经常主张给static的而且只用了一次的函数加上inline,如此不会有任何损失,因为没 665人们经常主张给 static 的而且只用了一次的函数加上 inline,如此不会有任何损失,因为没
605有什么好权衡的。虽然从技术上说这是正确的,但是实际上这种情况下即使不加inline gcc 666有什么好权衡的。虽然从技术上说这是正确的,但是实际上这种情况下即使不加 inline gcc
606也可以自动使其内联。而且其他用户可能会要求移除inline,由此而来的争论会抵消inline 667也可以自动使其内联。而且其他用户可能会要求移除 inline,由此而来的争论会抵消 inline
607自身的潜在价值,得不偿失。 668自身的潜在价值,得不偿失。
608 669
609 670
@@ -613,37 +674,37 @@ vmalloc()。请参考API文档以获取有关它们的详细信息。
613的一个值可以表示为一个错误代码整数(-Exxx=失败,0=成功)或者一个“成功”布尔值( 674的一个值可以表示为一个错误代码整数(-Exxx=失败,0=成功)或者一个“成功”布尔值(
6140=失败,非0=成功)。 6750=失败,非0=成功)。
615 676
616混合使用这两种表达方式是难于发现的bug的来源。如果C语言本身严格区分整形和布尔型变 677混合使用这两种表达方式是难于发现的 bug 的来源。如果 C 语言本身严格区分整形和布尔型变
617量,那么编译器就能够帮我们发现这些错误……不过C语言不区分。为了避免产生这种bug,请 678量,那么编译器就能够帮我们发现这些错误……不过 C 语言不区分。为了避免产生这种 bug,请
618遵循下面的惯例: 679遵循下面的惯例:
619 680
620 如果函数的名字是一个动作或者强制性的命令,那么这个函数应该返回错误代码整 681 如果函数的名字是一个动作或者强制性的命令,那么这个函数应该返回错误代码整
621 数。如果是一个判断,那么函数应该返回一个“成功”布尔值。 682 数。如果是一个判断,那么函数应该返回一个“成功”布尔值。
622 683
623比如,“add work”是一个命令,所以add_work()函数在成功时返回0,在失败时返回-EBUSY。 684比如,“add work” 是一个命令,所以 add_work() 函数在成功时返回 0,在失败时返回 -EBUSY。
624类似的,因为“PCI device present”是一个判断,所以pci_dev_present()函数在成功找到 685类似的,因为 “PCI device present” 是一个判断,所以 pci_dev_present() 函数在成功找到
625一个匹配的设备时应该返回1,如果找不到时应该返回0。 686一个匹配的设备时应该返回 1,如果找不到时应该返回 0。
626 687
627所有导出(译注:EXPORT)的函数都必须遵守这个惯例,所有的公共函数也都应该如此。私 688所有导出(译注:EXPORT)的函数都必须遵守这个惯例,所有的公共函数也都应该如此。私
628有(static)函数不需要如此,但是我们也推荐这样做。 689有(static)函数不需要如此,但是我们也推荐这样做。
629 690
630返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。一般的,他们 691返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。一般的,他们
631通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数,他们使用 692通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数,他们使用
632NULL或者ERR_PTR机制来报告错误。 693NULL 或者 ERR_PTR 机制来报告错误。
633 694
634 695
635 第十七章:不要重新发明内核宏 696 第十七章:不要重新发明内核宏
636 697
637头文件include/linux/kernel.h包含了一些宏,你应该使用它们,而不要自己写一些它们的 698头文件 include/linux/kernel.h 包含了一些宏,你应该使用它们,而不要自己写一些它们的
638变种。比如,如果你需要计算一个数组的长度,使用这个宏 699变种。比如,如果你需要计算一个数组的长度,使用这个宏
639 700
640 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 701 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
641 702
642类似的,如果你要计算某结构体成员的大小,使用 703类似的,如果你要计算某结构体成员的大小,使用
643 704
644 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) 705 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
645 706
646还有可以做严格的类型检查的min()和max()宏,如果你需要可以使用它们。你可以自己看看 707还有可以做严格的类型检查的 min() max() 宏,如果你需要可以使用它们。你可以自己看看
647那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应在你的代码里 708那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应在你的代码里
648自己重新定义。 709自己重新定义。
649 710
@@ -653,42 +714,100 @@ NULL或者ERR_PTR机制来报告错误。
653有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,emacs 714有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,emacs
654能够解释被标记成这样的行: 715能够解释被标记成这样的行:
655 716
656-*- mode: c -*- 717 -*- mode: c -*-
657 718
658或者这样的: 719或者这样的:
659 720
660/* 721 /*
661Local Variables: 722 Local Variables:
662compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" 723 compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
663End: 724 End:
664*/ 725 */
665 726
666Vim能够解释这样的标记: 727Vim 能够解释这样的标记:
667 728
668/* vim:set sw=8 noet */ 729 /* vim:set sw=8 noet */
669 730
670不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置,你的源文件不应 731不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置,你的源文件不应
671该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可以使用他们自己定制的模 732该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可以使用他们自己定制的模
672式,或者使用其他可以产生正确的缩进的巧妙方法。 733式,或者使用其他可以产生正确的缩进的巧妙方法。
673 734
674 735
736 第十九章:内联汇编
737
738在特定架构的代码中,你也许需要内联汇编来使用 CPU 接口和平台相关功能。在需要
739这么做时,不要犹豫。然而,当 C 可以完成工作时,不要无端地使用内联汇编。如果
740可能,你可以并且应该用 C 和硬件交互。
741
742考虑去写通用一点的内联汇编作为简明的辅助函数,而不是重复写下它们的细节。记住
743内联汇编可以使用 C 参数。
744
745大而特殊的汇编函数应该放在 .S 文件中,对应 C 的原型定义在 C 头文件中。汇编
746函数的 C 原型应该使用 “asmlinkage”。
747
748你可能需要将你的汇编语句标记为 volatile,来阻止 GCC 在没发现任何副作用后就
749移除了它。你不必总是这样做,虽然,这样可以限制不必要的优化。
750
751在写一个包含多条指令的单个内联汇编语句时,把每条指令用引号字符串分离,并写在
752单独一行,在每个字符串结尾,除了 \n\t 结尾之外,在汇编输出中适当地缩进下
753一条指令:
754
755 asm ("magic %reg1, #42\n\t"
756 "more_magic %reg2, %reg3"
757 : /* outputs */ : /* inputs */ : /* clobbers */);
758
759
760 第二十章:条件编译
761
762只要可能,就不要在 .c 文件里面使用预处理条件;这样做让代码更难阅读并且逻辑难以
763跟踪。替代方案是,在头文件定义函数在这些 .c 文件中使用这类的条件表达式,提供空
764操作的桩版本(译注:桩程序,是指用来替换一部分功能的程序段)在 #else 情况下,
765再从 .c 文件中无条件地调用这些函数。编译器会避免生成任何桩调用的代码,产生一致
766的结果,但逻辑将更加清晰。
767
768宁可编译整个函数,而不是部分函数或部分表达式。而不是在一个表达式添加 ifdef,
769解析部分或全部表达式到一个单独的辅助函数,并应用条件到该函数内。
770
771如果你有一个在特定配置中可能是未使用的函数或变量,编译器将警告它定义了但未使用,
772标记这个定义为 __maybe_unused 而不是将它包含在一个预处理条件中。(然而,如果
773一个函数或变量总是未使用的,就直接删除它。)
774
775在代码中,可能的情况下,使用 IS_ENABLED 宏来转化某个 Kconfig 标记为 C 的布尔
776表达式,并在正常的 C 条件中使用它:
777
778 if (IS_ENABLED(CONFIG_SOMETHING)) {
779 ...
780 }
781
782编译器会无条件地做常数合并,就像使用 #ifdef 那样,包含或排除代码块,所以这不会
783带来任何运行时开销。然而,这种方法依旧允许 C 编译器查看块内的代码,并检查它的正确
784性(语法,类型,符号引用,等等)。因此,如果条件不满足,代码块内的引用符号将不存在,
785你必须继续使用 #ifdef。
786
787在任何有意义的 #if 或 #ifdef 块的末尾(超过几行),在 #endif 同一行的后面写下
788注释,指出该条件表达式被使用。例如:
789
790 #ifdef CONFIG_SOMETHING
791 ...
792 #endif /* CONFIG_SOMETHING */
793
675 794
676 附录 I:参考 795 附录 I:参考
677 796
678The C Programming Language, 第二版, 作者Brian W. Kernighan和Denni 797The C Programming Language, 第二版
679M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (软皮), 798作者:Brian W. Kernighan 和 Denni M. Ritchie.
6800-13-110370-9 (硬皮). URL: http://cm.bell-labs.com/cm/cs/cbook/ 799Prentice Hall, Inc., 1988.
800ISBN 0-13-110362-8 (软皮), 0-13-110370-9 (硬皮).
681 801
682The Practice of Programming 作者Brian W. Kernighan和Rob Pike. Addison-Wesley, 802The Practice of Programming
683Inc., 1999. ISBN 0-201-61586-X. URL: http://cm.bell-labs.com/cm/cs/tpop/ 803作者:Brian W. Kernighan 和 Rob Pike.
804Addison-Wesley, Inc., 1999.
805ISBN 0-201-61586-X.
684 806
685cppgccgcc internalsindent的GNU手册——和K&R及本文相符合的部分,全部可以在 807GNU 手册 - 遵循 K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
686http://www.gnu.org/manual/找到 808都可以从 http://www.gnu.org/manual/ 找到
687 809
688WG14是C语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/ 810WG14是C语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
689 811
690Kernel CodingStyle,作者greg@kroah.com发表于OLS 2002: 812Kernel CodingStyle,作者 greg@kroah.com 发表于OLS 2002:
691http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ 813http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
692
693--
694最后更新于2007年7月13日。