Linux内核的CodingStyle

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主要为了下面的用途

  1. 完全不透明的类型(访问这些类型也需要对应的访问函数)

ex. pid_t, uid_t, pte_t … 等等

  1. 避免整型数据的困扰,比如int, long类型的长度在不同体系结构中不一致等等, 使用 u8/u16/u32 来代替整型定义
  2. 当使用kernel的sparse工具做变量类型检查时, 可以typedef一个类型.
  3. 定义C99标准中的新类型
  4. 为了用户空间的类型安全

内核空间的结构体映射到用户空间时使用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有可能忽略此请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值