2. 编码风格规范:命名规则与缩进风格
好,咱们聊聊命名这件事。说实话,我见过太多因为命名混乱导致的惨案了。有一次我接手一个项目,有个变量叫 tmp123,你猜它是干嘛的?我查了三天才搞明白,它居然是个全局状态标志。从那以后,我对命名这件事就特别较真。
2.1 变量命名:见名知意是底线
变量命名,说白了就是让别人一眼看懂你的意图。我个人习惯用 匈牙利命名法 的简化版,但别搞得太复杂。
核心原则:
- 局部变量:小写字母 + 下划线,如
temp_value、counter - 全局变量:加
g_前缀,如g_system_state - 静态变量:加
s_前缀,如s_initialized_flag - 指针变量:加
p_前缀,如p_buffer
// 好的命名
uint8_t g_sensor_temperature; // 一看就知道是全局传感器温度
static uint32_t s_heartbeat_count; // 静态的心跳计数
uint8_t *p_rx_buffer; // 接收缓冲区指针
// 糟糕的命名
uint8_t a; // 这是啥?
uint8_t temp1; // 哪个temp?
uint8_t data; // 什么数据?
我的小技巧:变量名长度控制在 8-20 个字符之间。太短了看不懂,太长了写代码累。比如 temperature_sensor_value 就太长了,改成 temp_sensor_val 刚刚好。
2.2 函数命名:动词开头,功能明确
函数命名我坚持一个原则:动词 + 名词 结构。你想想看,函数就是一段动作,所以动词开头最自然。
| 推荐写法 | 不推荐写法 | 说明 |
|---|---|---|
uart_send_byte() |
byte_send() |
动词 send 在前,清晰 |
gpio_set_pin() |
set() |
太笼统,不知道设哪个 |
timer_get_count() |
get_timer() |
获取的是计数值,不是定时器本身 |
注意:千万不要用 do_something()、handle()、process() 这种万能命名。我曾经在一个项目里看到 12 个 process() 函数,那场面...嗯,你懂的。
2.3 宏定义:全大写 + 下划线
宏定义这块,规矩很死。全大写加下划线,这是行业共识。为什么?因为宏是预处理器处理的,跟普通变量区分开,避免混淆。
// 正确的宏命名
#define BUFFER_SIZE 256
#define GPIO_PIN_LED (1U << 5)
#define MAX_RETRY_COUNT 3
// 函数式宏,也要全大写
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define IS_BIT_SET(val, bit) ((val) & (1U << (bit)))
避坑指南:我曾经见过有人把宏写成小写,结果跟局部变量重名了。调试了整整一天才发现是宏被覆盖了。所以记住:宏必须全大写,这是保护你的最后一道防线。
2.4 文件命名:模块化 + 层次化
文件命名我建议用 模块名_功能 的格式。比如你有个 UART 驱动,可以这样分:
uart_driver.c // UART 驱动主文件
uart_driver.h // UART 驱动头文件
uart_config.c // UART 配置相关
uart_config.h // UART 配置头文件
uart_private.h // 内部使用的私有定义
嗯,这里要注意:头文件和源文件必须成对出现。我见过有人只写 .c 文件不写 .h 文件,结果别人想调用他的函数,根本不知道有哪些接口可用。
2.5 缩进与括号风格:一致性压倒一切
缩进风格,说白了就是团队里统一就行。我个人偏爱 Allman 风格,就是括号单独占一行。为什么?因为这样括号对齐,代码结构一目了然。
// Allman 风格(我推荐的)
if (condition)
{
do_something();
do_another();
}
else
{
handle_error();
}
// K&R 风格(也常见)
if (condition) {
do_something();
do_another();
} else {
handle_error();
}
我的建议:不管选哪种风格,缩进统一用 4 个空格。别用 Tab,因为不同编辑器 Tab 宽度不一样。你想想看,代码在别人电脑上显示得乱七八糟,多尴尬。
2.6 命名规则速查表
| 元素 | 命名规则 | 示例 |
|---|---|---|
| 局部变量 | 小写 + 下划线 | temp_value |
| 全局变量 | g_ + 小写 |
g_system_state |
| 静态变量 | s_ + 小写 |
s_initialized |
| 函数 | 动词 + 名词 | uart_send_byte() |
| 宏 | 全大写 + 下划线 | BUFFER_SIZE |
| 文件 | 模块名_功能 | uart_driver.c |
| 类型定义 | _t 后缀 |
uart_config_t |
最后提醒一句:命名规则不是用来束缚你的,而是用来保护你的。我见过太多因为命名不规范导致的 bug,比如把 i 和 j 搞混、把 temp 和 tmp 弄反。这些低级错误,一套好的命名规则就能避免。
好了,命名规则这块就聊到这儿。记住:好的代码是自文档化的。你写的每一行代码,都应该像在跟别人说话一样清晰。下一章咱们聊聊注释规范,那也是个容易踩坑的地方。