4、注释风格基础:JavaDoc风格 vs. Qt风格,嵌入式C项目该选哪个?我的建议。
写注释这事儿,说实话,很多嵌入式工程师都不太当回事。
我见过不少项目,代码跑得挺稳,但一看注释——要么是十年前留下的「// 修改了bug」,要么干脆没有。你想想看,一个产品维护三五年,换了两三拨人,新来的同事看着一堆寄存器操作,心里得多崩溃。
所以今天咱们聊聊注释风格。具体来说,就是JavaDoc风格和Qt风格,到底哪个更适合嵌入式C项目。
4.1 两种风格长什么样?
先看个例子,你一眼就能分辨出来。
JavaDoc风格(也叫Doxygen的JavaDoc模式):
/**
* @brief 初始化UART外设
* @param uart_id: UART编号,取值范围0-2
* @param baudrate: 波特率,支持9600/19200/115200
* @return 0表示成功,-1表示参数错误
*/
int uart_init(uint8_t uart_id, uint32_t baudrate);
Qt风格:
/*!
* \brief 初始化UART外设
* \param uart_id UART编号,取值范围0-2
* \param baudrate 波特率,支持9600/19200/115200
* \return 0表示成功,-1表示参数错误
*/
int uart_init(uint8_t uart_id, uint32_t baudrate);
看出来区别了吗?
JavaDoc用@开头,Qt风格用\开头。本质上,它们都是Doxygen支持的标记方式。说白了,就是「钥匙」不一样,锁是同一把。
4.2 我个人更倾向哪个?
我直接说结论:嵌入式C项目,我建议选JavaDoc风格。
为什么?三个原因。
- 第一,JavaDoc风格更通用。 你写嵌入式代码,免不了要和上位机、测试脚本打交道。JavaDoc的
@param、@return这些标记,很多语言和工具都认识。Qt风格虽然也不错,但出了Qt生态,认识的人就少一些。 - 第二,团队协作成本低。 我在项目中遇到过,新来的同事以前写Java或者Python,看到
@brief秒懂。但看到\brief,他会愣一下:「咦,这是啥?」。你想想看,减少一个认知负担,就是减少一次沟通成本。 - 第三,工具链兼容性好。 Doxygen、Sphinx、甚至一些IDE的智能提示,对JavaDoc的支持都更成熟。我踩过Qt风格在某些老版本Doxygen上解析出错的坑,后来就彻底切回JavaDoc了。
我的建议: 嵌入式C项目,统一使用JavaDoc风格。Qt风格不是不能用,但除非你的团队全员都是Qt老手,否则别给自己找麻烦。
4.3 嵌入式C注释的「黄金三要素」
风格定下来之后,具体写什么?我总结了三样东西,缺一不可。
| 要素 | 说明 | 示例 |
|---|---|---|
| 函数功能 | 一句话说清楚这个函数干什么 | @brief 读取温度传感器数据 |
| 参数说明 | 每个参数的含义、范围、单位 | @param channel 通道号,0-7 |
| 返回值 | 成功/失败分别返回什么 | @return 温度值(℃),-1表示读取失败 |
嗯,这里要注意:不要写废话。
比如:
/**
* @brief 初始化函数
* @param a 参数a
* @param b 参数b
* @return 返回值
*/
int init(int a, int b);
这种注释写了等于没写。我见过太多这样的「僵尸注释」了,纯粹占地方。
4.4 避坑指南:我曾经踩过的三个坑
讲几个真实教训,你写注释的时候可以绕开。
- 坑一:注释和代码不同步。 我曾经接手过一个项目,注释里写着「@param timeout 超时时间,单位ms」,结果代码里实际用的是us。排查了一整天,最后发现是注释没更新。所以,改代码必须改注释,这是铁律。
- 坑二:过度注释。 有些新手喜欢每行都加注释,比如:
i++; // i加1。这完全没必要。注释应该解释「为什么这么做」,而不是「做了什么」。代码本身就能说明「做了什么」。 - 坑三:忽略文件头注释。 很多人只给函数加注释,文件开头啥也不写。我建议每个源文件和头文件都加一个文件头,包含:文件名、作者、创建日期、简要说明、修改记录。别小看这个,项目大了之后,找责任人全靠它。
小技巧: 如果你用VS Code,可以装一个Doxygen Documentation Generator插件。写函数的时候敲/**然后回车,模板自动生成,省时省力。
4.5 一个完整的嵌入式C注释示例
最后,给你看一个我实际项目中的注释模板。照着这个写,基本不会出错。
/**
* @file adc_driver.c
* @brief ADC外设驱动实现
* @author 张三
* @date 2024-01-15
* @note 修改记录:
* 2024-03-10 张三:增加DMA模式支持
* 2024-05-20 李四:修复通道切换时序问题
*/
/**
* @brief 初始化ADC指定通道
* @param ch ADC通道号,范围ADC_CH0 ~ ADC_CH7
* @param mode 采样模式,0:单次 1:连续 2:扫描
* @param clk_div 时钟分频系数,取值1/2/4/8
* @return 0:成功 -1:参数错误 -2:硬件初始化失败
* @note 调用前需确保ADC外设时钟已使能
*/
int adc_channel_init(adc_channel_t ch, uint8_t mode, uint8_t clk_div)
{
// 参数校验
if (ch > ADC_CH7) return -1;
if (mode > 2) return -1;
// 配置通道寄存器
ADC->CHSEL = ch;
ADC->MODE = mode;
ADC->CLKDIV = clk_div;
// 启动校准
ADC->CR |= (1 << 3);
while (ADC->SR & (1 << 3));
return 0;
}
你看,文件头、函数注释、关键代码注释都有了。而且注释都是解释「为什么」和「注意事项」,没有废话。
4.6 总结一下
注释风格这事儿,没有绝对的对错。但如果你问我,我会说:嵌入式C项目,选JavaDoc风格,配合Doxygen生成文档,是目前最稳妥的方案。
Qt风格不是不行,但通用性差一点。你想想看,万一哪天项目要对接Python或者Java的团队,JavaDoc风格的注释直接就能复用,多省心。
最后送你一句话:好注释不是写给自己看的,是写给三个月后的自己看的。那时候的你,大概率已经忘了当初为什么这么写。所以,现在多写一句,以后少掉一根头发。
警告: 不要为了注释而注释。如果你的代码逻辑清晰、命名规范,有些注释完全可以省略。注释是「锦上添花」,不是「雪中送炭」。烂代码加再多注释,也救不回来。