七夏 发表于 2025-2-6 14:01:10

统一代码注释规范

<h2>1.总则</h2>
<ul>
<li><strong>目的</strong>:提高代码的可读性和便于维护。</li>
<li><strong>清晰</strong>:注释应简洁明了,避免歧义,描述代码的目的、方法和背景信息;注释内容应聚焦于帮助理解代码。</li>
<li><strong>准确</strong>:确保注释和代码逻辑一致。</li>
<li><strong>适度</strong>:避免无意义的注释,必要时注释,不要过度。</li>
</ul>
<p><img src="https://www.3bbs.cn/index-diy/img.php?url=https://mmbiz.qpic.cn/sz_mmbiz_png/LhYwUvIicQJibOTriaKia9YI2h3c8ictKf5Hrr9kuGHjDLrk8HlKhJYmlYAialWQmzMgRI6eYtTZsaABhYIaVu1NcianA/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<h2>2.注释类型</h2>
<h3>2.1.文件注释</h3>
<h5>要求</h5>
<ul>
<li>每个源文件和头文件必须包含文件头注释,描述文件的功能、作者、日期和版本信息。</li>
</ul>
<h5>格式</h5>
<pre><code>/**
* @file ring_queue.h
* @brief 环形队列缓存区
* @author Eureka (eureka@mail.com)
* @version 1.0
* @date 2025-01-22
*
* @par 修改日志:
* &lt;table&gt;
* &lt;tr&gt;&lt;th&gt;Date       &lt;th&gt;Version &lt;th&gt;Author&lt;th&gt;Description
* &lt;tr&gt;&lt;td&gt;2025-01-22 &lt;td&gt;1.0   &lt;td&gt;Eureka   &lt;td&gt;首次创建
* &lt;/table&gt;
*
* @copyright Copyright (c) 2025Eureka
*/

</code></pre>
<h3>2.2.函数注释</h3>
<h5>说明</h5>
<p>标准规范下,应该需要在源文件中对函数进行注释,在头文件中不对函数进行注释(参考各个大厂MCU的HAL源码库可以看出)。这样做的好处是头文件中很简洁,可以快速查到到所需的API。</p>
<p>但在模块化的设计中,常常以库和头文件的形式提供模块,这种情况下,如果只在源码中注释了,被封装成库后,就无法看到注释的内容,鉴于此,内部约定规范要求如下:</p>
<h5>要求</h5>
<ul>
<li>如果是没有对外释放需要的代码,统一在源文件中进行注释,头文件中无需注释,只保留一份注释</li>
<li>标准化部门,统一对头文件中暴露的函数进行注释,所有非内联函数都应有函数头注释,说明其功能、参数和返回值</li>
</ul>
<h5>格式</h5>
<pre><code>/**
 * @brief 向其他主机发送数据
 * @param  host             主机节点
 * @param  ta               目标主机
 * @param  data             数据内容
 * @param  len              数据长度
 * @return &gt;=0::发送成功 其他:失败 参考 @ref TErrorCode  
 */
EXP_API int SonHostSend(int host, uint16_t ta, const uint8_t *data, int len);
</code></pre>
<h3>2.3.代码块注释</h3>
<h5>要求</h5>
<ul>
<li>复杂的代码块应在逻辑前添加注释,描述<strong>整体目的</strong>或<strong>关键步骤</strong>。</li>
<li>不推荐大篇幅的说明,对函数特殊的设计应该在设计文档中描述,而不是在代码中</li>
<li>如果实在注释内容较长,则进行多行注释,否则使用单行注释</li>
</ul>
<h5>示例</h5>
<pre><code>int example(void)
{
===================================
   // 写入非 _this-&gt;EscFlag 转义符
   while (pos &lt; end &amp;&amp; *pos != _this-&gt;EscFlag)
      pos++;

   // 检查尺寸是否溢出
   size = pos - begin;
   if (size &gt; _this-&gt;Rx.End - _this-&gt;Rx.Pos)
   {
      _this-&gt;RxLostBytes += _this-&gt;Rx.Total + size;
      L_TransInvalid(&amp;_this-&gt;Rx);
   }
   else
   {
      // 拷贝数据
      if (size &gt; 0)
      {
         memcpy(_this-&gt;Rx.Pos, begin, size);
         _this-&gt;Rx.BCC    = _this-&gt;DoBcc(begin, size, _this-&gt;Rx.BCC);
         _this-&gt;Rx.Pos   += size;
         _this-&gt;Rx.Total += size;
      }
=================================== 
}
</code></pre>
<h3>2.4.代码行注释</h3>
<h5>说明</h5>
<p>对代码中特殊操作或关键语句进行解释,尽量简洁。</p>
<h5>示例</h5>
<pre><code>result = get_gpio_level(0); ///&lt; 0为引脚值,参考mproc_gpi_board.c GPI_DRV_CHN_ACC
</code></pre>
<h3>2.5.构造数据注释</h3>
<h5>说明</h5>
<p>这里的构造数据是指在嵌入式C中常常定义的枚举和结构体以及函数指针等。</p>
<h5>要求</h5>
<ul>
<li>头文件中的结构体和枚举,必须对头和每个成员进行注释</li>
<li>函数指针参考函数注释方法进行注释</li>
</ul>
<h5>示例</h5>
<ul>
<li>枚举</li>
</ul>
<pre><code>/**
 * @brief 事件类型定义
 */
typedef enum TSonEventType
{
    kEventOnConnect    = 0,   ///&lt; 连接到网络
    kEventOnDisConnect = 1,   ///&lt; 网络断开
    kEventOnBusFault   = 2,   ///&lt; 网络故障
    kEventOnPageAck    = 3,   ///&lt; 寻呼应答
    kEventOnReceive    = 4,   ///&lt; 接收到数据
    kEventOnAckTimeout = 5,   ///&lt; 应答超时
}TEventType;
</code></pre>
<ul>
<li>结构体</li>
</ul>
<pre><code>/**
 * @brief TBOX配置数据
 */
typedef struct TTboxConfigType
{
    char    *ota_cert;         ///&lt; OTA服务器根证书
    char    *dl_cert;          ///&lt; 下载服务器根证书
    char    *tbox_cert;        ///&lt; TBOX证书
    char    *tbox_key;         ///&lt; TBOX私钥
    char    *vin;              ///&lt; VIN
    char    *tbox_part_no;     ///&lt; TBOX 零部件号
}TTboxConfig;
</code></pre>
<ul>
<li>函数指针</li>
</ul>
<pre><code>/**
 * @brief 消息接收回调函数指针
 * @param  owner             用户参数指针
 * @param  sa                数据源地址
 * @param  len               数据长度
 * @param  data              数据指针
 */
typedef void (*TOnReceive)(void *owner, uint16_t sa, int len, const uint8_t *data);
</code></pre>
<h2>3.注释格式</h2>
<h3>3.1.注释语法</h3>
<h5>说明</h5>
<p>为了满足 <code>API</code> 导出说明文档(使用 <code>doxgen</code> 工具导出)的需要,注释参数需要严格满足 <code>doxgen</code> 语法的需要</p>
<h5>单行注释</h5>
<ul>
<li>注释行:指注释单独占用一行,在 <code>C/C++</code> 中,单行使用 <code>*</code> 进行注释</li>
<li>行内注释:指在代码行的行尾进行注释,要求行尾注释使用 <code>*/&lt;</code> 进行注释</li>
</ul>
<h5>多行注释</h5>
<ul>
<li>多行注释参考 <code>C/C++</code>注释语法,使用</li>
</ul>
<pre><code>/*
* 注释内容1
* 注释内容2
* ...
*/
</code></pre>
<h5>文件头</h5>
<ul>
<li>使用多行注释</li>
<li><code>@file</code> 后面紧跟此文件的名称</li>
<li><code>@brief</code> 简述此文件的内容</li>
<li><code>@author</code> 此文件的第一作者</li>
<li><code>@version</code> 此文件当前的版本</li>
<li><code>@date</code> 此文件的最后一次修改时间</li>
<li><code>@par</code> 用于说明修改日志</li>
<li><code>@copyright</code> 权利约束说明</li>
</ul>
<h5>函数头</h5>
<ul>
<li><code>@brief</code> 说明此函数的作用</li>
<li><code>@param</code> 说明此函数的参数</li>
<li><code>@return</code> 说明返回值(如果无返回,则不需要此字段)</li>
</ul>
<h5>块注释</h5>
<p>用于注释结构体、枚举、代码块等。</p>
<pre><code>/**
 * @brief 概述此块内容
 */
</code></pre>
<h3>3.2.语言规范</h3>
<h5>要求</h5>
<ul>
<li>编码:统一使用 <code>UTF8</code></li>
<li>统一使用要求的语言(中文)注释,不允许两种及以上的语言混合注释</li>
<li>避免主观词汇,例如“也许”“可能”</li>
<li>禁止长篇大论</li>
<li>自己不清楚的不要注释,例如:张三说这个地方需要加一,否则功能会异常</li>
<li>一两句描述不清楚的,将详细的描述写入设计文档,在代码中加入说明引用来源,比如:<code>// 参考 《sonhost设计文档-V1.2.0.6.pdf》3.6.2</code></li>
</ul>
<h3>3.3.对齐缩进</h3>
<h5>要求</h5>
<ul>
<li>注释应对齐关键代码或结构体成员,保持视觉美观。</li>
</ul>
<h2>4.注释误区</h2>
<ul>
<li>不必要的注释</li>
<li>过于冗长的注释</li>
<li>注释不清晰,导致“反向注释”</li>
</ul>
<h2>5.快捷工具</h2>
<p>在vscode编辑器中,可以使用插件实现规范注释,如“Doxgen”插件,用于生成doxgen的语法参数,“Snippet”用于快捷插入注释。</p>
页: [1]
查看完整版本: 统一代码注释规范