Linux内核C语言代码规范
Linux内核C语言代码规范
一、命名规范详解
1. 变量/函数命名
/* 正确示例 */
int device_driver_count; // 设备驱动计数
void register_pci_device(void); // 注册PCI设备/* 错误示例 */
int DeviceCount; // 首字母大写
void RegisterPCI(); // 首字母大写+缩写
规范要求:
- 全小写
snake_case
,单词间用下划线连接 - 全局变量/函数需带模块前缀(如
pci_
,usb_
) - 避免缩写(除非广泛接受如
dev
)
2. 类型定义
/* 正确示例 */
struct list_head { // 链表头struct list_head *next, *prev;
};
typedef void (*irq_handler_t)(int, void*); // 中断处理函数指针/* 错误示例 */
typedef struct { // 匿名结构体int x, y;
} Point_t; // _t后缀用于基本类型
规范要求:
- 结构体/联合体使用
struct
关键字显式声明 typedef
仅用于函数指针和特定场景- 避免使用
_t
后缀(内核约定)
3. 宏命名
/* 正确示例 */
#define MAX_IRQ_NUM 256 // 常量宏
#define container_of(ptr, type, member) // 函数式宏((type *)((char *)(ptr) - offsetof(type, member)))/* 错误示例 */
#define MaxIrq 256 // 混合大小写
#define min(a,b) a<b?a:b // 缺少参数括号
规范要求:
- 常量宏全大写
SCREAMING_SNAKE_CASE
- 函数式宏使用小写和括号保护参数
- 多行宏用
do {...} while(0)
包裹
二、格式规范详解
1. 缩进与空格
/* 正确示例 */
if (irq < MAX_IRQ_NUM) { // 关键字后空格struct irq_desc *desc = &irq_desc[irq]; // *靠近变量名desc->handler(irq, desc->dev_id); // ->操作符无空格
}/* 错误示例 */
if(irq<MAX_IRQ_NUM){ // 缺少空格struct irq_desc* desc = &irq_desc [ irq ]; // *位置错误+多余空格
}
规范要求:
- 8字符Tab缩进(非空格)
- 关键字后加空格:
if (
,while (
- 指针声明:
char *ptr
(*
靠左) - 操作符两侧空格:
a = b + c
2. 大括号规则
/* 函数 */
int init_module(void) // 函数大括号独占一行
{/* ... */
}/* 语句块 */
if (condition) { // 左大括号同行do_this();do_that();
} else { // else单独一行do_otherwise();
}/* 单行语句 */
if (condition)single_statement(); // 无大括号但独占一行
3. 行长度与换行
/* 正确换行 */
static int process_packet(struct sk_buff *skb, struct net_device *dev,struct packet_type *pt)
{return netif_rx(skb) == NET_RX_SUCCESS ? 0 : -EIO;
}/* 错误换行 */
int result = function_with_long_name(argument1, argument2, argument3, argument4); // 错误:续行缩进不足
规范要求:
- 行长度≤100字符
- 续行对齐参数或操作符
- 函数参数过多时每行一个参数
三、文件组织规范
1. 头文件格式
#ifndef _LINUX_SCHED_H // 保护宏格式:_LINUX_<文件名>_H
#define _LINUX_SCHED_H#include <linux/pid.h> // 标准头文件
#include <asm/current.h> // 体系结构相关头文件/* 内联函数 */
static inline void __set_task_state(struct task_struct *tsk, int state)
{tsk->state = state;
}/* 函数声明 */
extern void scheduler_tick(void);#endif /* _LINUX_SCHED_H */
2. 源文件结构
/* * 文件注释:描述模块功能* Copyright (c) ... 许可证信息*/
#include <linux/module.h>
#include "internal.h" // 本地头文件#define LOCAL_DEBUG 0 // 本地宏定义static int instance_count; // 静态全局变量/* 主功能函数 */
int core_function(void)
{/* ... */
}/* 辅助函数 */
static void helper(void) // 静态函数
{/* ... */
}
四、内核特有规范
1. 错误处理模式
int device_probe(struct device *dev)
{int ret;struct resource *res;res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);if (!res)return -ENOMEM; // 直接返回错误码ret = device_init(res);if (ret < 0)goto err_init; // 错误时跳转清理ret = register_device(res);if (ret < 0)goto err_register;return 0;/* 逆向资源释放 */
err_register:device_deinit(res);
err_init:devm_kfree(dev, res);return ret;
}
2. 并发控制
static DEFINE_SPINLOCK(counter_lock);
static atomic_t online_devices = ATOMIC_INIT(0);void add_device(void)
{unsigned long flags;spin_lock_irqsave(&counter_lock, flags); // 保存中断状态atomic_inc(&online_devices);spin_unlock_irqrestore(&counter_lock, flags);
}
3. 内存管理
/* 标准分配 */
struct data *p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)return -ENOMEM;/* 清零分配 */
struct config *cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);/* 高性能对象池 */
static struct kmem_cache *data_cache;data_cache = kmem_cache_create("data_cache", sizeof(struct data), 0, SLAB_HWCACHE_ALIGN, NULL);
struct data *item = kmem_cache_alloc(data_cache, GFP_KERNEL);
五、注释规范
1. 函数注释
/*** irq_handler - 中断服务函数* @irq: 中断号* @dev_id: 设备标识指针** 处理来自设备的硬件中断,读取状态寄存器并* 调度下半部处理程序。** 返回: IRQ_HANDLED 表示成功处理*/
irqreturn_t irq_handler(int irq, void *dev_id)
{/* ... */return IRQ_HANDLED;
}
2. 数据结构注释
/** 进程描述符 - 内核中进程/线程的核心数据结构* * @state: 进程状态(运行、睡眠等)* @stack: 内核栈指针* @tasks: 用于链接到任务列表*/
struct task_struct {volatile long state;void *stack;struct list_head tasks;/* ... */
};
六、典型违规案例
案例1:命名不规范
// 错误
int DeviceCounter; // 首字母大写
#define MAXDEV 10 // 未全大写// 正确
int device_count;
#define MAX_DEVICES 10
案例2:指针声明位置错误
// 错误
char* buffer; // *靠近类型// 正确
char *buffer; // *靠近变量名
案例3:大括号使用错误
// 错误
if (condition)
{do_something(); // 左大括号单独一行
}// 正确
if (condition) {do_something();
}
七、工具使用示例
1. checkpatch.pl检查
$ ./scripts/checkpatch.pl -f --strict drivers/net/ethernet.c
2. 代码格式化
$ ./scripts/Lindent drivers/char/mydriver.c
3. 静态分析
$ make C=2 drivers/usb/
总结:Linux内核编码黄金法则
- 可读性优先:代码是给人看的,其次才是机器
- 一致性至上:严格遵循现有代码风格
- 内存安全:每次分配都要考虑释放路径
- 并发意识:假设代码会在多核环境运行
- 性能敏感:关键路径避免函数调用和分支
内核大师Linus Torvalds的忠告:“糟糕的代码不会被接受,无论它实现了多么炫酷的功能。良好的风格是进入内核社区的门票。”
通过严格遵守这些规范,开发者可以:
- 提高代码被主线接纳的概率
- 减少内存泄漏和竞态条件风险
- 增强代码可维护性和可读性
- 加速代码审查过程
- 建立良好的内核开发声誉