模块化编程中的代码规范:命名规范、格式化工具与审查清单
说实话,代码规范这事儿,我年轻时觉得是「形式主义」。那时候我写代码,变量名能省则省,什么 a、b、tmp 满天飞。直到有一次,一个项目交接给同事维护,对方看了三天代码,最后打电话问我:「老兄,你这个 p 到底是 pointer 还是 parameter?」——嗯,从那以后,我再也不敢乱起名字了。
今天咱们聊聊模块化编程里的三个硬功夫:命名规范、格式化工具、代码审查清单。这三样东西,说白了就是让你的代码「能读、能改、能交接」。
一、命名规范:两种主流流派
命名这件事,没有绝对的对错。但团队里必须统一。我见过最惨的案例是:一个项目里同时用了匈牙利命名法、下划线命名法、驼峰命名法,结果一个函数里变量名风格就换了三次。你想想看,这代码还怎么维护?
1. 匈牙利命名法
匈牙利命名法,核心思想是「变量名要体现类型信息」。比如:
int iCount; // i 表示 int
char *szName; // sz 表示 zero-terminated string
BOOL bIsReady; // b 表示 BOOL
HANDLE hFile; // h 表示 handle
我个人习惯在 Windows 驱动开发中用这套。为什么?因为驱动里类型转换频繁,看一眼变量名前缀,就知道它是什么类型,能避免不少低级错误。
2. 下划线命名法
下划线命名法,也叫「蛇形命名法」。Linux 内核、很多嵌入式 RTOS 都用这套。风格是:全小写,单词间用下划线分隔。
int buffer_size;
void uart_send_data(uint8_t *data, uint32_t len);
#define MAX_BUFFER_LEN 1024
我在做 STM32 项目时,团队就统一用下划线命名法。为什么?因为嵌入式代码里宏定义、枚举、函数名混在一起,下划线风格一眼就能看出「这是变量还是函数还是宏」。
__private_var),因为 C 标准保留给编译器内部使用。我曾经在 GCC 下踩过这个雷,编译报错查了半天,结果就是双下划线惹的祸。
3. 我推荐的混合策略
实际项目中,我建议这样组合:
| 元素 | 命名风格 | 示例 |
|---|---|---|
| 局部变量 | 下划线命名法 | int temp_value; |
| 全局变量 | 加前缀 g_ | int g_system_tick; |
| 函数名 | 模块名_动作 | uart_send_data() |
| 宏定义 | 全大写 + 下划线 | #define UART_BAUD_115200 |
| 类型定义 | 加 _t 后缀 | typedef struct {...} uart_config_t; |
这套规则我用了十年,团队里新人也容易上手。说白了,命名规范不是为了炫技,而是为了降低沟通成本。
二、代码格式化工具:clang-format
手动对齐代码?那是上个世纪的事了。我见过最夸张的团队,代码审查时一半时间在争论「大括号要不要换行」。后来我强制引入 clang-format,从此天下太平。
1. 什么是 clang-format
clang-format 是 LLVM 项目下的代码格式化工具。它可以根据配置文件,自动调整缩进、空格、换行、大括号位置等。说白了,你写完代码,一键格式化,风格就统一了。
2. 我的 .clang-format 配置
这是我个人项目里常用的配置,你可以直接拿去用:
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
BreakBeforeBraces: Allman
AllowShortFunctionsOnASingleLine: None
ColumnLimit: 100
PointerAlignment: Left
SpaceAfterCStyleCast: true
解释几个关键点:
- IndentWidth: 4 —— 缩进用 4 个空格。嵌入式代码嵌套深,4 空格比 2 空格更清晰。
- BreakBeforeBraces: Allman —— 大括号换行。我个人偏好这种风格,因为左括号单独一行,容易配对。
- ColumnLimit: 100 —— 每行最多 100 字符。太长了在屏幕上要滚动,太短了又容易断行。
.clang-format 文件,然后配置 Git 的 pre-commit 钩子,每次提交前自动格式化。这样团队里谁都不用操心格式问题。
3. 集成到编辑器
我常用的集成方式:
- VS Code:安装 C/C++ 扩展,设置
editor.formatOnSave: true - CLion:内置 clang-format 支持,直接配置路径即可
- Vim:用
vim-clang-format插件,一键:ClangFormat
你想想看,如果团队里每个人都用同一套格式化规则,代码审查时还会有人纠结「这里多了一个空格」吗?不会。大家只关注逻辑,效率翻倍。
三、代码审查清单:从「看代码」到「审代码」
代码审查不是走过场。我见过太多团队,审查就是「LGTM」(Looks Good To Me)三个字母。结果呢?上线后 bug 频出。真正的审查,应该有一份清单,逐项检查。
1. 我的审查清单模板
这是我多年积累的清单,分享给你:
| 类别 | 检查项 | 说明 |
|---|---|---|
| 命名规范 | 变量名是否体现用途? | 避免 a、b、tmp 等无意义命名 |
| 命名规范 | 宏定义是否全大写? | 如 #define BUFFER_SIZE 256 |
| 内存安全 | 指针使用前是否判空? | 尤其是函数参数和 malloc 返回值 |
| 内存安全 | 数组访问是否越界? | 检查循环边界条件 |
| 模块化 | 函数是否超过 50 行? | 超过则考虑拆分 |
| 模块化 | 全局变量是否过多? | 尽量用局部变量或参数传递 |
| 错误处理 | 函数返回值是否检查? | 尤其是系统调用和库函数 |
| 错误处理 | 是否有未处理的错误路径? | 如 switch 的 default 分支 |
| 可移植性 | 是否使用了平台相关代码? | 如有,是否用宏隔离? |
| 可移植性 | 字节序处理是否正确? | 网络通信中常见问题 |
2. 审查流程建议
我建议的流程是:
- 自审:提交前,开发者自己对照清单过一遍
- 互审:至少一位同事审查,重点关注逻辑和安全性
- 终审:架构师或技术负责人审查,关注整体设计
四、知识体系总览
下面这张图,帮你把今天的内容串起来:
你看,这三个方面其实是环环相扣的。命名规范让代码「看得懂」,格式化工具让代码「长得像」,审查清单让代码「靠得住」。缺一个,模块化编程就容易走样。
最后说一句:规范不是束缚,而是解放。当你不用再纠结「这个变量叫什么名字」时,你才能把精力真正放在「这个逻辑该怎么设计」上。嗯,这就是我这么多年最大的体会。