Chapter 1: Indentation(缩进)
缩进要使用tab键,并且tab键的宽度为8个字符
switch和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;
Chapter 2: Breaking long lines and strings(换行)
代码长度控制在80个字符以内,过长的代码需要换行,并且保持代码的可阅读性
printk(KERN_WARNING "Warning this is a long printk with "
"3 parameters a: %u b: %u "
"c: %u \n", a, b, c);
Chapter 3: Placing Braces and Spaces(括号和空格的位置)
3.1 大括号
非函数的代码块,左大括号不用另起一行
if (x is true) {
we do y
}
switch (action) {
case KOBJ_ADD:
return "add";
case KOBJ_REMOVE:
return "remove";
case KOBJ_CHANGE:
return "change";
default:
return NULL;
}
do {
body of do-loop
} while (condi)
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
只有一行的语句块不用大括号
if (condition)
action();
函数的代码块要单独占一行
int function(int x)
{
body of function
}
3.2 空格
下列关键字后面追加空格
if, switch, case, for, do, while
下列关键字后面不加空格
sizeof, typeof, alignof, or __attribute__.
s = sizeof( struct file );
双目运算符和三目运算符要加空格间隔开
= + - < > * / % | & ^ <= >= == != ? :
单目运算符,不论前置还是后置都不加空格
& * + - ~ ! sizeof typeof alignof __attribute__ defined
++ --
结构体成员访问运算符后面不加空格
. ->
Chapter 4: Naming(命名)
全局变量和函数需要有一个描述性的名称
count_active_users();
cntusr();
局部变量命名要简洁,例如:tmp
Chapter 5: Typedefs
尽量不要使用typedef,使用typedef主要为了下面的用途
- 完全不透明的类型(访问这些类型也需要对应的访问函数)
ex. pid_t, uid_t, pte_t … 等等
- 避免整型数据的困扰,比如int, long类型的长度在不同体系结构中不一致等等, 使用 u8/u16/u32 来代替整型定义
- 当使用kernel的sparse工具做变量类型检查时, 可以typedef一个类型.
- 定义C99标准中的新类型
- 为了用户空间的类型安全
内核空间的结构体映射到用户空间时使用typedef, 这样即使内核空间的数据结构有变化, 用户空间也能正常运行
Chapter 6: Functions(函数)
函数要简短,一个函数只做一件事情
函数长度一般不超过2屏(1屏的大小是 80x24), 也就是48行
如果函数中的 switch 有很多简单的 case语句, 那么超出2屏也可以
函数中局部变量不能超过 5~10 个
函数与函数之间空一行,但是和EXPORT*之间不用空
int one_func(void)
{
return 0;
}
int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
Chapter 7: Centralized exiting of functions(函数退出)
将函数的退出集中在一起, 特别有需要清理内存的时候.(goto 并不是洪水猛兽, 有时也很有用)
int fun(int a)
{
int result = 0;
char *buffer = kmalloc(SIZE);
if (buffer == NULL)
return -ENOMEM;
if (condition1) {
while (loop1) {
...
}
result = 1;
goto out;
}
...
out:
kfree(buffer);
return result;
}
Chapter 8: Commenting(注释)
注释code做了什么, 而不是如何做的
使用C89的注释风格(/* … */), 不要用C99的注释风格(// …)
Chapter 9: You’ve made a mess of it(控制缩进的方法)
(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)
(c-set-style "linux-tabs-only")))))
Chapter 10: Kconfig configuration files(Kconfig 配置文件)
config AUDIT
bool "Auditing support"
depends on NET
help
Enable auditing infrastructure that can be used with another
kernel subsystem, such as SELinux (which requires this for
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
不稳定的特性要加上EXPERIMENTAL
config SLUB
depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
bool "SLUB (Unqueued Allocator)"
...
危险的特性要加上DANGEROUS
config ADFS_FS_RW
bool "ADFS write support (DANGEROUS)"
depends on ADFS_FS
...
Chapter 11: Data structures(数据结构)
结构体要包含一个引用计数字段 (内核中没有自动垃圾收集, 需要手动释放内存)
需要保证结构体数据一致性时要加锁
结构体中有时甚至会需要多层的引用计数
ex. struc mm_struct, struct super_block
Chapter 12: Macros, Enums and RTL(宏、枚举类型和RTL)
宏定义常量常使用大写字母
#define CONSTANT 0x12345
宏定义多行语句时要放入 do - while 中, 此时宏的名称用小写
#define macrofun(a, b, c) \
do { \
if (a == 5) \
do_this(b, c); \
} while (0)
宏定义表达式要放在()中
#define CONSTANT 0x4000
#define CONSTEXP (CONSTANT | 3)
Chapter 13: Printing kernel messages(打印内核信息)
保持打印信息的简明清晰
比如, 不要用 “dont”, 而是使用 “do not” 或者 “don’t”
内核信息不需要使用 “.” 结尾
打印 “(%d)” 之类的没有任何意义, 应该避免
选择合适的打印级别(调试,还是警告,错误等等)
Chapter 14: Allocating memory(分配内存)
分配内存时sizeof(指针) 而不是 sizeof(结构体)
p = kmalloc(sizeof(*p), ...);
Chapter 15: The inline disease(内联的弊端)
如果一个函数有3行以上, 不要使用 inline 来标记它
Chapter 16: Function return values and names(函数的返回值及命名)
如果函数功能是一个动作或者一个命令时, 返回 int型的 error-code
比如, add_work() 函数执行成功时返回 0, 失败时返回对应的error-code(ex. -EBUSY)
如果函数功能是一个判断时, 返回 “0” 表示失败, “1” 表示成功
所有Exported函数, 公用的函数都要上述2条要求
所有私有(static)函数, 不强制要求, 但最好能满足上面2条要求
如果函数返回真实计算结果, 而不是是否成功时, 通过返回计算结果范围外的值来表示失败
比如一个返回指针的函数, 通过返回 NULL 来表示失败
Chapter 17: Don’t re-invent the kernel macros(不要重复发明内核宏)
内核定义的宏在头文件 include/linux/kernel.h 中, 想定义新的宏时, 首先看看其中是否已有类似的宏可用
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
Chapter 18: Editor modelines and other cruft(编辑器模式行和其他)
不要在代码中加入特定编辑器的内容或者其他工具的配置,
-*- mode: c -*-
/*
Local Variables:
compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
End:
*/
/* vim:set sw=8 noet */
Chapter 19: Inline assembly(内联汇编)
尽量不要使用内联汇编,一般汇编代码应该都在.S文件中的,也许你会使用volatile关键确保去寄存器中取值,但是gcc有可能忽略此请求