summaryrefslogtreecommitdiffstats
path: root/Documentation/translations/zh_CN/process/coding-style.rst
blob: 3cb09803e084683ce192441cf7f60b84fc7422ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
Chinese translated version of Documentation/process/coding-style.rst

If you have any comment or update to the content, please post to LKML directly.
However, if you have problem communicating in English you can also ask the
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>

以下为正文

---------------------------------------------------------------------

Linux 内核代码风格
=========================

这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的,
而且我不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则
那样,我也希望在绝大多数事上保持这种的态度。请 (在写代码时) 至少考虑一下这里
的代码风格。

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

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


1) 缩进
--------------

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

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

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

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

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

.. code-block:: c

	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;
	}

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

.. code-block:: c

	if (condition) do_this;
	  do_something_everytime;

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

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

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


2) 把长的行和字符串打散
------------------------------

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

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

长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性,并且不
会隐藏信息。子片段要明显短于母片段,并明显靠右。这同样适用于有着很长参数列表
的函数头。然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这样就
很难对它们 grep。


3) 大括号和空格的放置
------------------------------

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

.. code-block:: c

	if (x is true) {
		we do y
	}

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

.. code-block:: c

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

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

.. code-block:: c

	int function(int x)
	{
		body of function
	}

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

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

.. code-block:: c

	do {
		body of do-loop
	} while (condition);.. code-block:: c

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

理由:K&R。

也请注意这种大括号的放置方式也能使空 (或者差不多空的) 行的数量最小化,同时不
失可读性。因此,由于你的屏幕上的新行是不可再生资源 (想想 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 );

当声明指针类型或者返回指针类型的函数时, ``*`` 的首选使用方式是使之靠近变量名
或者函数名,而不是靠近类型名。例子:

.. 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 发现补丁包含了行尾空白的时候会警告你,并且可以应你的要求去掉行尾空白;
不过如果你是正在打一系列补丁,这样做会导致后面的补丁失败,因为你改变了补丁的
上下文。


4) 命名
------------------------------

C 是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同,
C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会
称那个变量为 ``tmp`` ,这样写起来会更容易,而且至少不会令其难于理解。

不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的
名字。称一个全局函数为 ``foo`` 是一个难以饶恕的错误。

全局变量 (只有当你 **真正** 需要它们的时候再用它) 需要有一个具描述性的名字,就
像全局函数。如果你有一个可以计算活动用户数量的函数,你应该叫它
``count_active_users()`` 或者类似的名字,你不应该叫它 ``cntuser()`` 。

在函数名中包含函数类型 (所谓的匈牙利命名法) 是脑子出了问题——编译器知道那些类
型而且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题
的程序。

本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计
数器,它应该被称为 ``i`` 。叫它 ``loop_counter`` 并无益处,如果它没有被误解的
可能的话。类似的, ``tmp`` 可以用来称呼任意类型的临时变量。

如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综
合症。请看第六章 (函数)。


5) Typedef
-----------

不要使用类似 ``vps_t`` 之类的东西。

对结构体和指针使用 typedef 是一个 **错误** 。当你在代码里看到:

.. code-block:: c

	vps_t a;

这代表什么意思呢?

相反,如果是这样

.. code-block:: c

	struct virtual_container *a;

你就知道 ``a`` 是什么了。

很多人认为 typedef ``能提高可读性`` 。实际不是这样的。它们只在下列情况下有用:

 (a) 完全不透明的对象 (这种情况下要主动使用 typedef 来 **隐藏** 这个对象实际上
     是什么)。

     例如: ``pte_t`` 等不透明对象,你只能用合适的访问函数来访问它们。

     .. note::

       不透明性和 "访问函数" 本身是不好的。我们使用 pte_t 等类型的原因在于真
       的是完全没有任何共用的可访问信息。

 (b) 清楚的整数类型,如此,这层抽象就可以 **帮助** 消除到底是 ``int`` 还是
     ``long`` 的混淆。

     u8/u16/u32 是完全没有问题的 typedef,不过它们更符合类别 (d) 而不是这里。

     .. note::

       要这样做,必须事出有因。如果某个变量是 ``unsigned long`` ,那么没有必要

	typedef unsigned long myflags_t;

     不过如果有一个明确的原因,比如它在某种情况下可能会是一个 ``unsigned int``
     而在其他情况下可能为 ``unsigned long`` ,那么就不要犹豫,请务必使用
     typedef。

 (c) 当你使用 sparse 按字面的创建一个 **新** 类型来做类型检查的时候。

 (d) 和标准 C99 类型相同的类型,在某些例外的情况下。

     虽然让眼睛和脑筋来适应新的标准类型比如 ``uint32_t`` 不需要花很多时间,可
     是有些人仍然拒绝使用它们。

     因此,Linux 特有的等同于标准类型的 ``u8/u16/u32/u64`` 类型和它们的有符号
     类型是被允许的——尽管在你自己的新代码中,它们不是强制要求要使用的。

     当编辑已经使用了某个类型集的已有代码时,你应该遵循那些代码中已经做出的选
     择。

 (e) 可以在用户空间安全使用的类型。

     在某些用户空间可见的结构体里,我们不能要求 C99 类型而且不能用上面提到的
     ``u32`` 类型。因此,我们在与用户空间共享的所有结构体中使用 __u32 和类似
     的类型。

可能还有其他的情况,不过基本的规则是 **永远不要** 使用 typedef,除非你可以明
确的应用上述某个规则中的一个。

总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们
就不应该是一个 typedef。


6) 函数
--------------------