2、命名规范(上):变量命名、函数命名、宏命名、文件命名
命名这件事,说大不大,说小不小。我见过太多项目,代码逻辑写得挺好,一看命名——全是一堆 a、b、tmp、data1、data2……你想想看,三个月后你自己回来看,能记得 data1 是啥意思吗?
我个人习惯是:命名就是给代码写注释。好的命名,根本不需要额外注释。今天咱们就把变量、函数、宏、文件这四类命名规则捋清楚。
2.1 变量命名:见名知意,别偷懒
变量命名是基本功。我刚开始写代码时也图省事,用 i、j、k 满天飞。后来有一次调试一个电机控制程序,满屏的 cnt1、cnt2、cnt3,我盯着看了半小时才分清楚哪个是速度计数、哪个是位置计数。从那以后,我再也不敢乱起名了。
2.1.1 命名风格:小驼峰 + 下划线
嵌入式 C 语言里,我推荐小驼峰 + 下划线混合风格。具体来说:
- 局部变量:小驼峰,比如
motorSpeed、adcValue - 全局变量:加前缀
g_,比如g_systemTick、g_temperature - 静态变量:加前缀
s_,比如s_lastError、s_bufferIndex
核心原则:变量名要能准确描述它的用途和数据类型。
举个例子:
// 不好的命名
int a;
int b;
int c;
// 好的命名
int motorSpeed; // 电机转速
int adcRawValue; // ADC 原始采样值
int errorCode; // 错误码
2.1.2 常见变量类型命名模板
我整理了一个常用模板,你可以直接套用:
| 变量类型 | 命名模板 | 示例 |
|---|---|---|
| 计数器 | xxxCount |
retryCount |
| 标志位 | xxxFlag |
timeoutFlag |
| 索引 | xxxIndex |
bufferIndex |
| 状态 | xxxStatus |
motorStatus |
| 时间 | xxxTimeMs |
delayTimeMs |
小技巧:变量名里带上单位,比如 timeoutMs、speedRpm,能避免很多单位换算的 bug。我在项目中吃过这个亏,一个时间参数没写单位,结果有人传了秒、有人传了毫秒……
2.2 函数命名:动词开头,职责清晰
函数命名比变量命名更讲究。为什么?因为函数是代码的「动词」,它要做一件事,名字就得把这件事说清楚。
2.2.1 命名风格:动词 + 名词
我建议函数名采用动词 + 名词结构。动词表明操作,名词表明操作对象。
// 不好的命名
void process(void);
void handle(void);
void doSomething(void);
// 好的命名
void uartSendByte(uint8_t data);
int i2cReadRegister(uint8_t regAddr);
void ledSetBrightness(uint8_t level);
2.2.2 常用动词前缀
这里我列几个常用的动词前缀,都是我在实际项目中反复用到的:
| 动词 | 含义 | 示例 |
|---|---|---|
get |
获取值 | getTemperature |
set |
设置值 | setMotorSpeed |
init |
初始化 | initUart |
is |
判断真假 | isTimeout |
enable |
使能 | enableInterrupt |
disable |
禁止 | disableWatchdog |
注意:函数名不要超过 30 个字符。太长的函数名说明这个函数可能做了太多事,该拆分了。我曾经接手过一个叫 processAndUpdateAndSendAndLog 的函数……嗯,你懂的。
2.3 宏命名:全大写 + 下划线,别犹豫
宏的命名规则最统一,也最简单——全大写 + 下划线。这一点几乎没什么争议。
2.3.1 常量宏
#define BUFFER_SIZE 256
#define TIMEOUT_MS 1000
#define MAX_RETRY_COUNT 3
2.3.2 函数式宏
函数式宏也遵循全大写规则,但要注意参数用括号包好,避免展开出问题。
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(x) ((x) > 0 ? (x) : -(x))
#define IS_BIT_SET(x, b) ((x) & (1UL << (b)))
避坑指南:宏名不要和变量名、函数名冲突。我曾经在一个项目里看到有人定义了 #define delay 100,结果代码里所有叫 delay 的变量都被替换成了 100……编译报错报了一整天。
2.4 文件命名:模块化 + 层次化
文件命名是很多人容易忽略的。其实文件命名直接决定了项目的可维护性。
2.4.1 命名规则:模块名_功能
我推荐用模块名_功能的格式。模块名小写,功能部分小写,用下划线分隔。
// 好的文件命名
uart_driver.c
uart_driver.h
motor_control.c
motor_control.h
sensor_temperature.c
sensor_temperature.h
// 不好的文件命名
my_code.c
test.c
utils.c
common.c
2.4.2 头文件与源文件对应
每个 .c 文件都应该有一个对应的 .h 文件,文件名相同。这是基本要求。
| 源文件 | 头文件 | 说明 |
|---|---|---|
uart_driver.c |
uart_driver.h |
UART 驱动模块 |
motor_control.c |
motor_control.h |
电机控制模块 |
sensor_temperature.c |
sensor_temperature.h |
温度传感器模块 |
个人经验:文件名不要超过 40 个字符。太长的文件名在 Git 里看着难受,在文件系统里也容易出问题。另外,文件名里不要用空格和中文,这个应该不用我多说了吧?
2.5 本章知识体系
下面这张图帮你梳理了本章的核心内容,建议保存下来当 cheat sheet 用。
好了,命名规范的上半部分就讲到这里。变量、函数、宏、文件这四类命名,说白了就是一句话:别让读你代码的人猜。你写的时候觉得理所当然,别人看的时候可能就是一头雾水。
下一章咱们继续聊命名规范的下半部分——结构体、枚举、联合体、类型定义这些更复杂的命名场景。到时候我会分享一些我在大型项目里踩过的坑,保证让你少走弯路。