material/program/c_cpp/coding-style.md

144 lines
5.2 KiB
Markdown
Raw Permalink Normal View History

# Linux 内核代码风格(修改版)
## **缩进**
缩进的全部意义就在于清楚的定义一个控制块起止于何处,好的缩进是会当你的函数嵌套太深的时候可以给你警告,如果你需要3级以上的缩进,不管用何种方式你的代码已经有问题了,应该修正你的程序
也不要在一行里放多个赋值语句,内核代码风格超级简单,就是避免可能导致别人误读的表达式
除了注释-文档和 Kconfig 之外,不要使用空格来缩进,选用一个好的编辑器,不要在行尾留空格
---
## **把长的行和字符串打散**
代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性
每一行的长度的限制是 80 列,我们强烈建议您遵守这个惯例
这同样适用于有着很长参数列表的函数头
然而,绝对不要打散对用户可见的字符串
---
## **大括号和空格的放置**
把起始大括号放在行尾,而把结束大括号放在行首,这适用于所有的非函数语句块
```c
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;
}
```
函数的起始大括号放置于下一行的开头
```c
int function(int x)
{
body of function
}
```
(大多数)关键字后要加一个空格,值得注意的例外是 `sizeof, typeof, alignof, __attribute__`,这些关键字某些程度上看起来更像函数,所以在这些关键字之后放一个空格:
`if, switch, case, for, do, while`
不要在小括号里的表达式两侧加空格
在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符
`= + - < > * / % | & ^ <= >= == != ? :`
当声明指针类型或者返回指针类型的函数时, * 的首选使用方式是使之靠近变量名 或者函数名,而不是靠近类型名
但是一元操作符后不要加空格
`& * + - ~ ! ++ --`
---
## **命名**
C 是一个简朴的语言,你的命名也应该这样
全局变量(只有当你*真正*需要它们的时候再用它)需要有一个具描述性的名字,就像全局函数
本地变量名应该简短,而且能够表达相关的含义
- 变量/函数:小写 + 下划线
- 宏/枚举:全大写 + 下划线
- 结构体/类型
- 结构体名struct `my_struct_s`
- Typedef 类型名:`my_type_t`
总的来说,如果一个指针或者一个结构体里的元素可以合理的被直接访问到,那么它们 就不应该是一个 typedef
---
## **函数**
函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完 (我们 都知道 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好
函数的另外一个衡量标准是本地变量的数量。此数量不应超过 510 个,否则你的函数 就有问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松的同时跟踪 7 个不同的事物,如果再增多的话,就会糊涂了
在函数原型中包含参数名和它们的数据类型
---
## **集中的函数退出途径**
当一个函数从多个位置退出并且需要做一些类似清理的常见操作时goto 语句就很方便了。如果并不需要清理操作,那么直接 return 即可
使用 goto 的理由是:
- 无条件语句容易理解和跟踪
- 嵌套程度减小
- 可以避免由于修改时忘记更新个别的退出点而导致错误
- 让编译器省去删除冗余代码的工作
---
## **注释**
注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的,更好的做法是让别人一看你的代码就可以明白,一般来说你用注释告诉别人你的代码做了什么,而不是怎么做的
长 (多行) 注释的首选风格是:
```c
/*
* This is the preferred style for multi-line
* comments in the Linux kernel source code.
* Please use it consistently.
*
* Description: A column of asterisks on the left side,
* with beginning and ending almost-blank lines.
*/
```
注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行应只声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据写一段小注释来解释它们的用途了
---
## **数据结构**
如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引用计数器
引用计数意味着你能够避免上锁,并且允许多个用户并行访问这个数据结构
---
## **宏枚举和RTL**
用于定义常量的宏的名字及枚举里的标签需要大写
在定义几个相关的常量时,最好用枚举
宏的名字请用大写字母,不过形如函数的宏的名字可以用小写字母
含有多个语句的宏应该被包含在一个 do-while 代码块里
```c
#define macrofun(a, b, c) \
do { \
if (a == 5) \
do_this(b, c); \
} while (0)
```