2. 编码风格规范:命名规则与缩进风格

好,咱们聊聊命名这件事。说实话,我见过太多因为命名混乱导致的惨案了。有一次我接手一个项目,有个变量叫 tmp123,你猜它是干嘛的?我查了三天才搞明白,它居然是个全局状态标志。从那以后,我对命名这件事就特别较真。

2.1 变量命名:见名知意是底线

变量命名,说白了就是让别人一眼看懂你的意图。我个人习惯用 匈牙利命名法 的简化版,但别搞得太复杂。

核心原则:

  • 局部变量:小写字母 + 下划线,如 temp_valuecounter
  • 全局变量:加 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,比如把 ij 搞混、把 temptmp 弄反。这些低级错误,一套好的命名规则就能避免。

好了,命名规则这块就聊到这儿。记住:好的代码是自文档化的。你写的每一行代码,都应该像在跟别人说话一样清晰。下一章咱们聊聊注释规范,那也是个容易踩坑的地方。