1.总则
- 目的:提高代码的可读性和便于维护。
- 清晰:注释应简洁明了,避免歧义,描述代码的目的、方法和背景信息;注释内容应聚焦于帮助理解代码。
- 准确:确保注释和代码逻辑一致。
- 适度:避免无意义的注释,必要时注释,不要过度。

2.注释类型
2.1.文件注释
要求
- 每个源文件和头文件必须包含文件头注释,描述文件的功能、作者、日期和版本信息。
格式
/**
* @file ring_queue.h
* @brief 环形队列缓存区
* @author Eureka (eureka@mail.com)
* @version 1.0
* @date 2025-01-22
*
* @par 修改日志:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2025-01-22 <td>1.0 <td>Eureka <td>首次创建
* </table>
*
* @copyright Copyright (c) 2025 Eureka
*/
2.2.函数注释
说明
标准规范下,应该需要在源文件中对函数进行注释,在头文件中不对函数进行注释(参考各个大厂MCU的HAL源码库可以看出)。这样做的好处是头文件中很简洁,可以快速查到到所需的API。
但在模块化的设计中,常常以库和头文件的形式提供模块,这种情况下,如果只在源码中注释了,被封装成库后,就无法看到注释的内容,鉴于此,内部约定规范要求如下:
要求
- 如果是没有对外释放需要的代码,统一在源文件中进行注释,头文件中无需注释,只保留一份注释
- 标准化部门,统一对头文件中暴露的函数进行注释,所有非内联函数都应有函数头注释,说明其功能、参数和返回值
格式
/**
* @brief 向其他主机发送数据
* @param host 主机节点
* @param ta 目标主机
* @param data 数据内容
* @param len 数据长度
* @return >=0::发送成功 其他:失败 参考 @ref TErrorCode
*/
EXP_API int SonHostSend(int host, uint16_t ta, const uint8_t *data, int len);
2.3.代码块注释
要求
- 复杂的代码块应在逻辑前添加注释,描述整体目的或关键步骤。
- 不推荐大篇幅的说明,对函数特殊的设计应该在设计文档中描述,而不是在代码中
- 如果实在注释内容较长,则进行多行注释,否则使用单行注释
示例
int example(void)
{
===================================
// 写入非 _this->EscFlag 转义符
while (pos < end && *pos != _this->EscFlag)
pos++;
// 检查尺寸是否溢出
size = pos - begin;
if (size > _this->Rx.End - _this->Rx.Pos)
{
_this->RxLostBytes += _this->Rx.Total + size;
L_TransInvalid(&_this->Rx);
}
else
{
// 拷贝数据
if (size > 0)
{
memcpy(_this->Rx.Pos, begin, size);
_this->Rx.BCC = _this->DoBcc(begin, size, _this->Rx.BCC);
_this->Rx.Pos += size;
_this->Rx.Total += size;
}
===================================
}
2.4.代码行注释
说明
对代码中特殊操作或关键语句进行解释,尽量简洁。
示例
result = get_gpio_level(0); ///< 0为引脚值,参考mproc_gpi_board.c GPI_DRV_CHN_ACC
2.5.构造数据注释
说明
这里的构造数据是指在嵌入式C中常常定义的枚举和结构体以及函数指针等。
要求
- 头文件中的结构体和枚举,必须对头和每个成员进行注释
- 函数指针参考函数注释方法进行注释
示例
/**
* @brief 事件类型定义
*/
typedef enum TSonEventType
{
kEventOnConnect = 0, ///< 连接到网络
kEventOnDisConnect = 1, ///< 网络断开
kEventOnBusFault = 2, ///< 网络故障
kEventOnPageAck = 3, ///< 寻呼应答
kEventOnReceive = 4, ///< 接收到数据
kEventOnAckTimeout = 5, ///< 应答超时
}TEventType;
/**
* @brief TBOX配置数据
*/
typedef struct TTboxConfigType
{
char *ota_cert; ///< OTA服务器根证书
char *dl_cert; ///< 下载服务器根证书
char *tbox_cert; ///< TBOX证书
char *tbox_key; ///< TBOX私钥
char *vin; ///< VIN
char *tbox_part_no; ///< TBOX 零部件号
}TTboxConfig;
/**
* @brief 消息接收回调函数指针
* @param owner 用户参数指针
* @param sa 数据源地址
* @param len 数据长度
* @param data 数据指针
*/
typedef void (*TOnReceive)(void *owner, uint16_t sa, int len, const uint8_t *data);
3.注释格式
3.1.注释语法
说明
为了满足 API
导出说明文档(使用 doxgen
工具导出)的需要,注释参数需要严格满足 doxgen
语法的需要
单行注释
- 注释行:指注释单独占用一行,在
C/C++
中,单行使用 *
进行注释
- 行内注释:指在代码行的行尾进行注释,要求行尾注释使用
*/<
进行注释
多行注释
/*
* 注释内容1
* 注释内容2
* ...
*/
文件头
- 使用多行注释
@file
后面紧跟此文件的名称
@brief
简述此文件的内容
@author
此文件的第一作者
@version
此文件当前的版本
@date
此文件的最后一次修改时间
@par
用于说明修改日志
@copyright
权利约束说明
函数头
@brief
说明此函数的作用
@param
说明此函数的参数
@return
说明返回值(如果无返回,则不需要此字段)
块注释
用于注释结构体、枚举、代码块等。
/**
* @brief 概述此块内容
*/
3.2.语言规范
要求
- 编码:统一使用
UTF8
- 统一使用要求的语言(中文)注释,不允许两种及以上的语言混合注释
- 避免主观词汇,例如“也许”“可能”
- 禁止长篇大论
- 自己不清楚的不要注释,例如:张三说这个地方需要加一,否则功能会异常
- 一两句描述不清楚的,将详细的描述写入设计文档,在代码中加入说明引用来源,比如:
// 参考 《sonhost设计文档-V1.2.0.6.pdf》3.6.2
3.3.对齐缩进
要求
4.注释误区
- 不必要的注释
- 过于冗长的注释
- 注释不清晰,导致“反向注释”
5.快捷工具
在vscode编辑器中,可以使用插件实现规范注释,如“Doxgen”插件,用于生成doxgen的语法参数,“Snippet”用于快捷插入注释。