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风格的注释直接就能复用,多省心。

最后送你一句话:好注释不是写给自己看的,是写给三个月后的自己看的。那时候的你,大概率已经忘了当初为什么这么写。所以,现在多写一句,以后少掉一根头发。

警告: 不要为了注释而注释。如果你的代码逻辑清晰、命名规范,有些注释完全可以省略。注释是「锦上添花」,不是「雪中送炭」。烂代码加再多注释,也救不回来。