编程(代码、软件)规范(适用嵌入式、单片机、上位机等)

目录

前言

第1章 文件

1.1 头文件

1.2 定义文件

第2章 注释规范

2.1 共性注释规范

2.2 文档注释规范

2.3 C语言风格注释规范

第3章 排版规范

3.1 缩进与对齐 风格

3.2 空行

3.3 代码行

3.4 代码行内的空格

3.5 长行拆分

第4章 标识符命名规范

4.1 共性命名规则

4.2 文件命名规则

4.3 变量命名规则

4.4 函数命名规则

4.5 宏的命名规则

第5章 变量

第6章 常量、宏

第7章 数据类型

附件1 常用单词缩写(英文)(元音:aeiou)

附件2 常用反义词组(英文)

附件3 Doxygen格式常用关键字表

附件4 标识符命名个人风格

附件5 常见标识符命名风格种类


前言

        本编程规范是个人工作十几年来,近些年形成较为稳定的版本,已被工作的公司采纳为公司编程规范!本规范主要借鉴了一些大公司(华为,百度,腾讯,阿里巴巴,谷歌,苹果,微软,ARM,ST.....)的编程规范和风格,吸收它们的共性和个别优秀的地方。在一些细节方面请教了一些几十年的老工程师和一些华为等大公司软件工程师!

       本人曾创造过自己的编程风格,也曾想创造出世界上最完美的编程规范和风格,在当时的技术水平和行业局限下,自我感觉还是挺好的!随着经验的丰富,接触的技术越来越多,发现当初的一些规则和适用的环境已不再适用,甚至有些鸡肋,还增加了负担!在这方面也耗费很多没有价值的时间!后来痛定思痛改变编程规范和风格。不再原创,要与世界接轨,用符合当下所处大行业较为流行的,大公司通用的、大公司个别优秀的风格规范作为自己的编程规范和风格,简单说就是吸收大家之长处和共性,这样换了工作也能适用,新人进入也能快速适应,因为这些大多数人的规范和风格,少数服从多数。

        不要试图去创造最完美的编程规范和风格,每种风格都有长处和短处,这些不是我们的工作重心!编程规范和风格是为了给人看的,方便人们交流和阅读,每个人的喜欢都不同,很难满足和统一,如同世界很难统一一样。做到求同存异,兼容并包就可以了!编程规范和风格好与坏对芯片来说都一样,最终都要被翻译成机器码的!

第1章 文件

        每个 C++/C 程序通常分为两个文件。一个文件用于保存程序的声明(declaration),称为头文件。另一个文件用于保存程序的实现(implementation),称为定义(definition)文件。

        C++/C 程序的头文件以“.h”为后缀,C 程序的定义文件以“.c”为后缀,C++程序的定义文件通常以“.cpp”为后缀(也有一些系统以“.cc”或“.cxx”为后缀)。

1.1 头文件

        对于C语言来说,头文件的设计体现了大部分的系统设计。不合理的头文件布局是编译时间过长的根因。头文件主要由三部分内容组成:头文件注释;预处理块;函数声明等。

        通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。

        某产品曾经做过一个实验,把所有函数的实现通过工具注释掉,其编译时间只减少了不到10%,究其原因,在于A包含B,B包含C,C包含D,最终几乎每一个源文件都包含了项目组所有的头文件,从而导致绝大部分编译时间都花在解析头文件上。

        某产品更有一个“优秀实践”,用于将.c文件通过工具合并成一个比较大的.c文件,从而大幅度提高编译效率。其根本原因还是在于通过合并.c文件减少了头文件解析次数。但是,这样的“优秀实践”是对合理划分.c文件的一种破坏。

        大部分产品修改一处代码,都得需要编译整个工程,对于TDD之类的实践,要求对于模块级别的编译时间控制在秒级,即使使用分布式编译也难以实现,最终仍然需要合理的划分头文件、以及头文件之间的包含关系,从根本上降低编译时间。

    《google C++ Style Guide》1.2 头文件依赖 章节也给出了类似的阐述:若包含了头文件aa.h,则就引入了新的依赖:一旦aa.h被修改,任何直接和间接包含aa.h代码都会被重新编译。如果aa.h又包含了其他头文件如bb.h,那么bb.h的任何改变都将导致所有包含了aa.h的代码被重新编译,在敏捷开发方式下,代码会被频繁构建,漫长的编译时间将极大的阻碍频繁构建。因此,我们倾向于减少包含头文件,尤其是在头文件中包含头文件,以控制改动代码后的编译时间。

合理的头文件划分体现了系统设计的思想,但是从编程规范的角度看,仍然有一些通用的方法,用来合理规划头文件。本章节介绍的一些方法,对于合理规划头文件会有一定的帮助。

原则1.1.1  头文件适合放置对外接口的声明,不适合放置实现,实现应放在定义文件中。

说明:头文件是模块(Module)或单元(Unit)的对外接口。变量定义应在.c中定义,在.h中仅声明,尽量不要使用全局变量作为接口,变量是程序内部实现细节,应通过函数接口的方式对外暴露。

个人理解如下:

h文件:包含需用头文件、对外类型和枚举、对外宏(常量)定义、对外变量声明(尽量不用)、对外函数声明。

c文件:包含同名头文件、内部类型和枚举、内部宏(常量)定义、内部变量定义、内部函数定义与实现。
延伸阅读材料:《C语言接口与实现》(David R. Hanson 著 傅蓉 周鹏 张昆琪 权威 译 机械工业出版社 2004年1月)(英文版: "C Interfaces and Implementations")

原则1.1.2  头文件应当职责单一

说明:头文件过于复杂,依赖过于复杂是导致编译时间过长的主要原因。很多现有代码中头文件过大,职责过多,再加上循环依赖的问题,可能导致为了在.c中使用一个宏,而包含十几个头文件。

例如: 如下是某平台定义WORD类型的头文件:

#include 

#include 

#include 

#include 

…

typedef unsigned short WORD;

…

        这个头文件不但定义了基本数据类型WORD,还包含了stdio.h syslib.h等等不常用的头文件。如果工程中有10000个源文件,而其中100个源文件使用了stdio.h的printf,由于上述头文件的职责过于庞大,而WORD又是每一个文件必须包含的,从而导致stdio.h/syslib.h等可能被不必要的展开了9900次,大大增加了工程的编译时间。

规则1.1.1  每一个.c文件应有一个同名.h文件,用于声明需要对外公开的接口。

规则1.1.2  禁止头文件循环依赖。

说明:头文件循环依赖,是指a.h包含b.hb.h包含c.hc.h包含a.h之类。

规则1.1.3  头文件应当自包含。

说明:自包含是指任意一个头文件均可独立编译。如果a文件用到b文件内容,本应该a文件包含b.h头文件即可但要包含b.h头文件前还要先包含c.h头文件才能工作的话,增添不必要的负担。

例如: a文件用到b文件内容

#include "c.h" //要想用b文件,a文件必须先包含c.h文件,这种情况就不是自包含。
#include "b.h" //a文件本应该包含b.h就可以。

规则1.1.4  .c/.h文件禁止包含用不到的头文件。

规则1.1.5  用#include  格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。

规则1.2.6  用#include“filename.h”格式来引用非标准库的头文件(编译器将从用户工作目录开始搜索)。

规则1.1.7  为防止头文件被重复引用,应用ifndef/define/endif 结构产生预处理。命名格式:FILENAME_H_。

说明:没有在宏最前面加上“_",是因为一般以"_"和”__"开头的标识符为系统保留或者标准库使用,在有些静态检查工具中,若全局可见的标识符以"_"开头会给出告警。后面加"_"是为了与程序用的宏定义区别。

例如:

#idndef LED_H_ //很明显这一部分也是为了防止重复引用

#define LED_H_

……

#endif /* LED_H_ */

规则1.1.8  禁止在头文件中定义变量。

说明:在头文件中定义变量,将会由于头文件被其他.c文件包含而导致变量重复定义。

规则1.1.9   禁止在extern "C"中包含头文件。(来自华为编程规范)

说明:在extern "C"中包含头文件,会导致extern "C"嵌套,Visual Studio对extern "C"嵌套层次有限制,嵌套层次太多会编译错误。在extern "C"中包含头文件,可能会导致被包含头文件的原有意图遭到破坏。

错误示例:

extern “C”
{
#include “xxx.h”
...
}

正确示例:

#include “xxx.h”
extern “C”
{
...
}

建议1.1.1  C程序头文件中加extern "C"。

说明:extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言(而不是C++)的方式进行编译。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。

示例:  led头文件

#ifndef LED_H_ //很明显这一部分也是为了防止重复引用
#define LED_H_

#include"xxxx.h"

#ifdef __cplusplus //C++编译环境中(cpp文件定义了)定义了宏__cplusplus (plus plus就是"+ +"的意思)
extern "C"{ // 声明括号内是C语言代码,告诉C++编译器用C语言进行编译,这样C++就可以调用C头文件了
#endif

… //其他代码

#ifdef __cplusplus
}
#endif

#endif  /* LED_H_ */

建议1.2.2  头文件中只存放“声明”而不存放“定义”。

建议1.2.3  不提倡使用全局变量,尽量不要在头文件中出现象 extern int value 这类声明。

建议1.2.4  一个模块通常包含多个.c文件,建议放在同一个目录下,目录名即为模块名。为方便外部使用者,建议每一个模块提供一个.h,文件名为目录名。

说明:需要注意的是,这个.h并不是简单的包含所有内部的.h,它是为了模块使用者的方便,对外整体提供的模块接口。

建议1.2.5  如果一个模块包含多个子模块,则建议每一个子模块提供一个对外的.h,文件名为子模块名。

说明:降低接口使用者的编写难度。

建议1.2.6  同一产品统一包含头文件排列方式。

说明:常见的包含头文件排列方式:功能块排序、文件名升序、稳定度排序。建议以稳定度排序。

#include 
#include 
#include "平台头文件" //MCU厂家、系统等头文件
#include "第三方头文件" //公司或第三方提供的成熟头文件
#include "自己写的基础全局头文件"
          //base.h基础头文件,提供常用的数据类型、修饰符以及基础操作宏
          //global.h包含了其他基础的应用的头文件,第一个文件包含在应用相关c文件中。

#include "自己写的工具头文件"
#include "本项目头文件"
#include "本文头文件"

  

1.2 定义文件

        定义文件主要由三部分内容:定义文件注释;头文件的引用;程序的实现体(包括数据和代码)。

        函数设计的精髓:编写整洁函数,同时把代码有效组织起来。代码要求简单直接、不隐藏设计者的意图、用干净利落的抽象和直截了当的控制语句将函数有机组织起来。

        代码的有效组织包括:逻辑层和物理层两个方面。逻辑层,主要是把不同功能的函数通过某种联系组织起来,主要关注模块间的接口,也就是模块的架构。物理层,无论使用什么样的目录或者名字空间等,需要把函数用一种标准的方法组织起来。例如:设计良好的目录结构、函数名字、文件组织等,这样可以方便查找。

原则1.2.1  一个函数仅完成一件功能。

说明:一个函数实现多个功能给开发、使用、维护都带来很大的困难。

原则1.2.2  重复代码应该尽可能提炼成函数。

说明:重复代码提炼成函数可以带来维护成本的降低。

规则1.2.1  避免函数过长,新增函数不超过50行(非空非注释行)。

说明:本规则仅对新增函数做要求,对已有函数修改时,建议不增加代码行。

规则1.2.2  避免函数的代码块嵌套过深,新增函数的代码块嵌套不超过4层。

说明:本规则仅对新增函数做要求,对已有的代码建议不增加嵌套层次。

规则1.2.3  设计高扇入,合理扇出(小于7)的函数。

说明:扇出是指一个函数直接调用(控制)其它函数的数目,而扇入是指有多少上级函数调用它。扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,例如:总是1,表明函数的调用层次可能过多,这样不利于程序阅读和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。通常函数比较合理的扇出(调度函数除外)通常是3~5。

规则1.2.4  可重入函数应避免使用共享变量;若使用则应通过互斥手段(关中断、信号量)对其加以保护。

说明:可重入函数是指可能被多个任务并发调用的函数。在多任务操作系统中,函数具有可重入性是多个任务可以共用此函数的必要条件。共享变量指的全局变量和static变量。

规则1.2.5  废弃代码(没有被调用的函数和变量)要及时清除。

建议1.2.1  函数不变参数使用const。

说明:不变的值更易于理解/跟踪和分析,把const作为默认选项,在编译时会对其进行检查,使代码更牢固/更安全。

建议1.2.2  函数应避免使用全局变量、静态局部变量和I/O操作,不可避免的地方应集中使用。

建议1.2.3  检查函数所有非参数输入的有效性,如数据文件、公共变量等。

说明:函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入,即非参数输入。函数在使用输入参数之前,应进行有效性检查。

建议1.2.4  函数的参数个数不超过5个。

说明:函数的参数过多,会使得该函数易于受外部(其他部分的代码)变化的影响,从而影响维护工作。函数的参数过多同时也会增大测试的工作量。如果超过了5个建议拆分为不同函数。

建议1.2.5  除打印类函数外,不要使用可变长参函数。

说明:可变长参函数的处理过程比较复杂容易引入错误,而且性能也比较低,使用过多的可变长参函数将导致函数的维护难度大大增加。

建议1.2.6  在源文件范围内声明和定义的所有函数,除非外部可见,否则应该增加static关键字。

说明:如果一个函数只是在同一文件中的其他地方调用,那么就用static声明。使用static确保只是在声明它的文件中是可见的,并且避免了和其他文件或库中的相同标识符发生混淆的可能性。

第2章 注释规范

        良好的注释可以提高程序的可读性、易防错性、易维护性等。

2.1 共性注释规范

原则2.1.1  优秀的代码可以自我解释,不通过注释即可轻易读懂。

说明:优秀的代码不写注释也可轻易读懂,注释无法把糟糕的代码变好,需要很多注释来解释的代码往往存在坏味道,需要重构。

原则2.1.2  注释的内容要清楚、明了,含义准确,防止注释二义性。 

说明:错误的注释不但无益反而有害。

原则2.1.3  在代码的功能、意图层次上进行注释,提供有用、额外的信息。 

说明:注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。 

示例:如下注释意义不大。 

/* if receive_flag is TRUE */
if (receive_flag)

而如下的注释则给出了额外有用的信息。 

/* if mtp receive a message from links */
if (receive_flag)

规则2.1.1  边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。

规则2.1.2  避免在注释中使用缩写,除非是通用或标准的缩写。 

说明:在使用缩写时或之前,应对缩写进行必要的说明。

规则2.1.3  标识符命名中若使用特殊约定或缩写,则要有注释说明。

规则2.1.4  同一产品或项目组 注释格式统一。

规则2.1.5  注释应与其描述的代码相靠近。

规则2.1.6  注释应放在其代码上方相邻位置或右方,不可放在下面。如放于上方则需与其上面的代码用空行隔开,且与下方代码缩进相同。如放于代码后面则与代码空一格。

说明:可使程序排版整齐,并方便注释的阅读与理解。

建议2.1.1  避免在一行代码或表达式的中间插入注释。 

说明:除非必要,不应在代码或表达中间插入注释,否则容易使代码可理解性变差。

建议2.1.2  注释应考虑程序易读及外观排版的因素,使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达。 

说明:注释语言不统一,影响程序易读性和外观排版,出于对维护人员的考虑,建议使用中文。

2.2 文档注释规范

规则2.2.1  对于要生成帮助文档的注释,采用工具可识别的注释格式。风格要统一。注释字符长度≤80。

说明:采用工具可识别的注释格式,例如Doxygen格式,方便工具导出注释形成帮助文档。(常见工具:Doxygen,JavaDoc,……)

示例:单行注释格式 1 采用风格:/** …… */  ///……  放在代码上行,表示注释下行代码

单行注释格式 2 采用风格:/**< …… */ 或 ///<…… 放在代码后面表示注释前面代码

多行块注释格式 采用风格:/**

……

*/

规则2.2.2  项目、文件、函数、全局变量、全局常量、全局类型定义的注释格式采用工具可识别格式

规则2.2.3  文件注释必须列出:版权说明、首页标签、工程名称、作者、工号、源码文档路径、项目详细描述、功能描述、用法描述、固件更新记录等。

示例:以doxygen格式为例(Doxygen格式常用关键字表,见附件1),注释风格如下:

/** @copyright Copyright(c)2014-2011 XXXX Co.,Ltd. All rights reserved.
  ******************************************************************************
  * @mainpage   无人机固件程序
  * 
  * 
Project  A600   *
Author   缪某某(ID:123456)   *
Source   D:\workspace\demo_project\examples\A600\A600-doxygen   *
  * @section    项目描述   * 该无人机是主要应用于......   *   * @section    功能描述   * -# 定高悬停   * -# 路径规划飞行   *   * @section    用法描述   * -# 用遥控器   *   * @section    固件更新记录   *   *   *   *   *
Date        H_Version   S_Version       Author  Description  
2018/08/17  1.0         S02010041808171 lebo    创建初始版本
2019/06/24  1.1         S02010041906241 lebo       * -# 无   *
  ******************************************************************************   */

规则2.2.4  文件注释必须列出:版权说明、作者、工号、版本号、生成日期、概要内容、注解说明功能、注意事项、修改日志等。

示例:以doxygen格式为例,注释格式 风格如下:

/** @copyright  Copyright(c)2014-2011 XXXX Co.,Ltd. All rights reserved.
  ******************************************************************************
  * @mainpage   FreeRTOS实验
  * 
  * 
Project FreeRTOSDemo *
Author 匠在江湖(ID:1234) *
Source F:\BaiduNetdiskWorkspace\Work\FreeRTOSDemo *
* @section 项目描述   * - 类别1   *     -# 情况1......   *     -# 情况2......   * - 类别2   *     -# 情况1......   *     -# 情况2...... * @section 用法描述 * * @section 固件更新记录 * * * *
Date H_Version S_Version Author(ID:xxxxxx) Description
2018/08/17 1.0 S02010041808171 匠在江湖(ID:1234) 创建初始版本
****************************************************************************** */

规则2.2.5  函数注释必须列出:概要、参数、返回值等。根据实际情况增加相关项。

示例1:以doxygen格式为例,注释格式 风格如下:

/**
  ******************************************************************************
  * @brief   发送接收 模拟函数
  * @param   None
  * @retval  None
  * @note    
  ******************************************************************************
  */

示例2:

/**
  ******************************************************************************
  * @brief  xxx 函数
  * @param  None
  * @return 函数执行结果
  * - E_SUCCESS 成功
  * - E_FAIL 失败
  * @par 示例:
  * @code
  *    int ret = register_all(&data, len, RT_TYPE_T1)
  * @endcode
  * @see :: xx表  
  ******************************************************************************
  */

示例3:

/**
  ******************************************************************************
  * @brief  Register a User ADC Callback
  *         To be used instead of the weak predefined callback
  * @param  hadc Pointer to a ADC_HandleTypeDef structure that contains
  *         the configuration information for the specified ADC.
  * @param  CallbackID ID of the callback to be registered
  *         This parameter can be one of the following values:
  *          @arg @ref HAL_ADC_CONVERSION_COMPLETE_CB_ID      ADC conversion complete callback ID
  *          @arg @ref HAL_ADC_CONVERSION_HALF_CB_ID          ADC conversion complete callback ID
  *          @arg @ref HAL_ADC_LEVEL_OUT_OF_WINDOW_1_CB_ID    ADC analog watchdog 1 callback ID
  *          @arg @ref HAL_ADC_ERROR_CB_ID                    ADC error callback ID
  *          @arg @ref HAL_ADC_INJ_CONVERSION_COMPLETE_CB_ID  ADC group injected conversion complete callback ID
  *          @arg @ref HAL_ADC_MSPINIT_CB_ID                  ADC Msp Init callback ID
  *          @arg @ref HAL_ADC_MSPDEINIT_CB_ID                ADC Msp DeInit callback ID
  *          @arg @ref HAL_ADC_MSPINIT_CB_ID MspInit callback ID
  *          @arg @ref HAL_ADC_MSPDEINIT_CB_ID MspDeInit callback ID
  * @param  pCallback pointer to the Callback function
  * @retval HAL status
  ******************************************************************************
  */

示例4:

/**
  ******************************************************************************
  * @brief  Enables ADC, starts conversion of regular group and transfers result
  *         through DMA.
  *         Interruptions enabled in this function:
  *          - DMA transfer complete
  *          - DMA half transfer
  *          - overrun (if available)
  *         Each of these interruptions has its dedicated callback function.
  * @note   Case of multimode enabled (for devices with several ADCs): This
  *         function is for single-ADC mode only. For multimode, use the
  *         dedicated MultimodeStart function.
  * @param  hadc ADC handle
  * @param  pData The destination Buffer address.
  * @param  Length The length of data to be transferred from ADC peripheral to memory.
  * @retval None
  ******************************************************************************
  */

建议2.2.6  类型定义列出:类型名称、概要等。根据实际情况增加相关项。

示例1:以doxygen格式为例,注释格式 风格如下:

/** @enum BoolTypeE
  * @brief 布尔类型(逻辑型变量的定义符)
  */
typedef enum
{
    E_FALSE = 0, //假(错误)
    E_TRUE = !E_FALSE //真(正确)
}BoolTypeE;

示例2以doxygen格式为例,注释格式 风格如下:

/** @struct info
  * @brief 信息结构体 \n
  * 定义存储的信息
  */
typedef struct 结构体名字
{
   成员1, ///< 简要说明文字, 如果不加< 则会认为是成员2的注释
   成员2, ///< 简要说明文字
   成员3, ///< 简要说明文字
}结构体别名;

建议2.2.7  模块定义:模块组号 + 模块组名等。根据实际情况增加相关项。

示例1纯定义。模块组号 MCU_Driver, 模块名 MCU Driver

/**
  * @defgroup MCU_Driver MCU Driver
  */

或

/**  @defgroup MCU_Driver MCU Driver */

示例2定义 + 概要描述

/** @defgroup MCU_Driver MCU Driver
  * @brief
  */

示例3定义 + 组范围

/** @defgroup MCU_Driver MCU Driver
  * @{
  */

......

/** @} end of MCU_Driver */

示例3定义 + 组范围,加入到 MCU_Driver 模块组中,成为其子组

/** @defgroup ADC_C_Includes ADC.C Includes
  * @ingroup  MCU_Driver
  * @{
  */

#include "base.h"
#include "adc.h"

/** @} end of ADC_C_Includes */

2.3 C语言风格注释规范

规则2.3.1  不用生成注释文档 的注释, 采用编程语言标准注释格式。风格要统一。注释字符长度≤80。

示例:多行或单行注释格式 采用风格:/* …… */

只可单行注释格式 采用风格://…… 

建议2.3.1  包含头文件,类型定义,常量定义,宏定义,变量定义,函数定义与声明 要用注释划分模块,以便程序清晰易读

建议2.3.2  定义文件中 包含头文件,类型定义,宏定义,变量定义,函数定义 注释风格。

/** @copyright  Copyright(c)2014-2011 XXXX Co.,Ltd. All rights reserved.
  ******************************************************************************
  * @file       mcu.c
  * @brief      
  * @details    
  * @author     匠在江湖(ID:1234)
  * @version    V1.0
  * @date       2014/05/08
  ******************************************************************************
  * @attention
  * 
  * @par 修改日志:
  * 
  * 
  * 
  * 
Date Version Author(ID:xxxxxx) Description
2014/05/08 V1.0 匠在江湖(ID:1234) 创建初始版本
****************************************************************************** */ /* Includes *******************************************************************/ ……用户定义内容 /* Private typedef ************************************************************/ ……用户定义内容 /* Private constants **********************************************************/ ……用户定义内容 /* Private macro **************************************************************/ ……用户定义内容 /* Private variables **********************************************************/ ……用户定义内容 /* Private function prototypes ************************************************/ ……用户定义内容 /** ****************************************************************************** * @brief MCU 初始化 函数 * @param None * @return None * @note ****************************************************************************** */ void MCU_Init(void) { } /********************************* END OF FILE ********************************/

建议2.3.3  头文件中 包含头文件,类型定义,常量定义,宏定义,函数声明 注释风格。

/** @copyright  Copyright(c)2014-2011 XXXX Co.,Ltd. All rights reserved.
  ******************************************************************************
  * @file       mcu.h
  * @brief      与硬件相关的寄存器定义,包含头文件等。为了适用平台的转换
  * @details    
  * @author     匠在江湖(ID:1234)
  * @version    V1.0
  * @date       2014/05/08
  ******************************************************************************
  * @attention
  * 
  * @par 修改日志:
  * 
  * 
  * 
  * 
Date Version Author(ID:xxxxxx) Description
2014/05/08 V1.0 匠在江湖(ID:1234) 创建初始版本
****************************************************************************** */ #ifndef MCU_H_ #define MCU_H_ /* Includes *******************************************************************/ #include "stm32f1xx.h" #include "stm32f1xx_hal.h" #include "main.h" #include "usart.h" #include "base.h" #include "iwdg.h" #ifdef __cplusplus extern "C"{ #endif /* Exported types *************************************************************/ /* Exported constants *********************************************************/ /* Exported macro *************************************************************/ ///NOP() #define NOP() __NOP ///清看门狗 #define CLR_WDG() HAL_IWDG_Refresh(&hiwdg) //清看门狗 /* Exported functions *********************************************************/ void MCU_Init(void); #ifdef __cplusplus } #endif #endif /* MCU_H_ */ /********************************* END OF FILE ********************************/

建议2.3.4  在程序块的结束行右方加注释标记,以表明某程序块的结束。 

说明:当代码段较长,特别是多重嵌套时,这样做可以使代码更清晰,更便于阅读。 

示例:参见如下例子。 

if (...)
{
    // program code

    while (index < MAX_INDEX)
    {
        // program code
    } /* end of while (index < MAX_INDEX) */ // 指明该条while语句结束

    // program code
} /* end of if (...)*/ // 指明是哪条if语句结束 

第3章 排版规范

        良好的排版可以提高程序的可读性、易防错性、易维护性等。

3.1 缩进与对齐 风格

规则3.1.1  程序块要采用缩进风格编写,缩进的空格数为4个。 不轻易使用TAB键。

说明:编辑器可用TAB键代替空格时方可使用,否则程序会因缩进不同而变乱。

规则3.1.2  程序块的分界符(如C/C++语言的大括号{})应各独占一行并且位于同一列,同时与引用它们的语句左对齐。{ }之内的代码块在‘{’右边数格处左对齐。

说明:在函数体的开始、类的定义、结构的定义、枚举的定义以及iffordowhileswitchcase语句中的程序都要采用如上的缩进方式。 

示例:

​​​​​​​如下例子不符合规范。 
for (...) {
... // program code
}

应如下书写。 
for (...)
{
... // program code
}

3.2 空行

规则3.2.1  在每个类声明之后、每个函数定义结束之后都要加空行。

规则3.2.2  在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应

加空行分隔。

3.3 代码行

规则3.3.1  不允许把多个短语句写在一行中,即一行只写一条语句。 

示例:

​​​​​​​如下例子不符合规范。 
rect.length = 0; rect.width = 0;

应如下书写 
rect.length = 0;
rect.width = 0;

规则3.3.2  iffordowhilecaseswitchdefault等语句自占一行,且iffordowhile等语句的执行语句部分无论多少都要加括号{} 

示例:

​​​​​​​如下例子不符合规范。 
if (pUserCR == NULL) return;

应如下书写: 
if (pUserCR == NULL)
{
    return;
}

3.4 代码行内的空格

规则3.4.1  关键字之后要留空格。象const、virtual、inline、case 等关键字之后至少要留一个空格,否则无法辨析关键字。象if、for、while 等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。

规则3.4.2  函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。

规则3.4.3  ‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。

规则3.4.4  ‘,’之后要留空格,如Function(x, y, z)。如果‘;’不是一行的结束符号,其后要留空格,如for (initialization; condition; update)。

规则3.4.5  赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格。

规则3.4.6  一元操作符如“!”、“~”、“++”、“--”、“&”(地址运算符)等前后不加空格。

规则3.4.7  像“[]”、“.”、“->”这类操作符前后不加空格。

建议3.4.1  对于表达式比较长的for 语句和if 语句,为了紧凑起见可以适当地去掉一些空格,如for (i=0; i<10; i++)和if ((a<=b) && (c<=d))

建议3.4.2  代码或注释结束后不要有多余的空格,防止空格后面有未知东西。

如下会存在未知隐患

编程(代码、软件)规范(适用嵌入式、单片机、上位机等)_第1张图片

应该如下

编程(代码、软件)规范(适用嵌入式、单片机、上位机等)_第2张图片

3.5 长行拆分

规则3.5.1  代码行不要过长,最长不超过80 个字符。否则眼睛看不过来,也不便于打印。

规则3.5.2  长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。

示例: 

if( (very_longer_variable1 >= very_longer_variable12)
 && (very_longer_variable3 <= very_longer_variable14)
 && (very_longer_variable5 <= very_longer_variable16))
{
    dosomething();
}

第4章 标识符命名规范

        规范的标识符命名可以提高程序的可读性、易防错性、易维护性等。标识符命名的种类繁多,各有优缺点。没有一种命名规则可以让所有的程序员赞同,程序设计教科书一般都不指定命名规则。命名规则对软件产品而言并不是“成败悠关”的事,我们不要化太多精力试图发明世界上最好的命名规则,而应当制定一种令大多数项目成员满意的命名规则,并在项目中贯彻实施。本章仅提出了大多都认可的规范,对于命名风格可依下面规范作为指导思想参考附件常见的风格。

4.1 共性命名规则

共性规则是被大多数程序员采纳的,我们应当在遵循这些共性规则的前提下,再扩充特定的规则。

原则4.1.1  标识符的命名要清晰、明了,有明确含义,使用完整的英文单词或大家基本可以理解的缩写,避免使人产生误解,让人快速理解你的代码很重要。

说明:较短的单词可通过去掉元音形成缩写;较长的单词可取单词的头几个字母形成缩写;一些单词有大家公认的缩写。

示例: temp缩写为tmp;flag缩写为flg;message缩写为msg。

规则4.1.1  产品/项目组内部应保持统一的命名风格。

说明:Unix like(小写下划线)和windows like(大小写混排)风格均有其支持者,产品应根据自己的部署平台,选择其中一种,并在产品内部保持一致。 不要使用大小写与下划线混排的方式,用作特殊标识如标识成员变量、全局变量或静态变量的m_g_s_,其后加上大小写混排的方式是允许的。

示例:Add_User不允许;add_userAddUserm_AddUser允许。

规则4.1.2  程序中不要出现仅靠大小写区分的相似的标识符。

示例:x 与 X 容易混淆。

建议4.1.1  用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

示例: min/max ……

建议4.1.2  尽量避免名字中出现数字编号,除非逻辑上的确需要编号。

示例:

​​​​​​​如下命名,使人产生疑惑。
#define _EXAMPLE_0_TEST_

应改为有意义的单词命名 
#define _EXAMPLE_UNIT_TEST_

建议4.1.3  标识符前不应添加模块、项目、产品、部门的名称作为前缀。

说明:很多已有代码中已经习惯在文件名中增加模块名,这种写法类似匈牙利命名法,导致文件名不可读,并且带来如下问题:第一眼看到的是模块名,而不是真正的文件功能,阻碍阅读;文件名太长;文件名和模块绑定,不利于维护和移植。若foo.c进行重构后,从a模块挪到b模块,若foo.c中有模块名,则需要将文件名从a_module_foo.c改为b_module_foo.c 。

建议4.1.4  平台/驱动等适配代码的标识符命名风格保持和平台/驱动一致。

说明:涉及到外购芯片以及配套的驱动,这部分的代码变动(包括为产品做适配的新增代码),应该保持原有的风格。

建议4.1.5  重构/修改部分代码时,应保持和原有代码的命名风格一致。

说明:根据源代码现有的风格继续编写代码,有利于保持总体一致。

4.2 文件命名规则

建议4.2.1  文件命名统一采用小写字符。

说明:因为不同系统对文件名大小写处理会不同(如MS的DOS、Windows系统不区分大小写,但是Linux系统则区分),所以代码文件命名建议统一采用全小写字母命名。

4.3 变量命名规则

规则4.3.1  全局变量应增加“g_”前缀。

规则4.3.2  静态变量应增加“s_”前缀。

说明:全局变量十分危险,增加前缀更加醒目,名字丑陋,促使开发人员小心和少使用。从根本上来说,尽量不使用全局变量。

规则4.3.3  禁止使用单个字符命名变量,但ijk作局部循环变量是允许的。

建议4.3.1  变量的名字应当使用“名词”或者“形容词+名词”。

建议4.3.2  全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。类的成员函数应当只使用“动词”,被省略掉的名词就是对象本身。

4.4 函数命名规则

建议4.4.1  函数命名应以函数要执行的动作命名,一般采用动词或者动词+名词的结构。

建议4.4.2  函数指针除了前缀,其他按照函数的命名规则命名。

4.5 宏的命名规则

规则4.4.1  对于数值或者字符串等常量的定义,建议采用全大写字母,单词之间加下划线的方式命名(枚举同样建议使用此方式定义)

规则4.4.2 除了编译开关/头文件等特殊应用,应避免使用_EXAMPLE_TEST_之类以下划线开始和结尾的定义。

说明:一般来说,“_”开头、结尾的宏都是一些内部的定义,ISO/IEC 9899(俗称C99)中有描述。

第5章 变量

原则5.1.1 一个变量只有一个功能,不能把一个变量作多种用途。

原则5.1.2 结构单一,不要设计面面俱到的结构。

原则5.1.3 不用或者少用全局变量。

规则5.1.1 防止局部变量与全局变量重名。

规则5.1.2 通讯过程中使用的结构,必须注意字节序。

规则5.1.3 严禁使用未经初始化的变量作为右值

说明:在首次使用前初始化变量,初始化的地方离使用的地方越近越好,可以有效避免未初始化错误。

建议5.1.1 构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问全局变量,防止多个模块或函数都可以修改、创建同一全局变量的现象。

说明:降低全局变量耦合度。

建议5.1.2 使用面向接口编程思想,通过API访问数据:如果本模块的数据需要对外部模块开放,应提供接口函数来设置、获取,同时注意注意全局数据的访问互斥。

建议5.1.3 明确全局变量初始化的顺序,避免跨模块初始化的依赖。

建议5.1.4 尽量减少没有必要的数据类型默认转换或强制转换。

第6章 常量、宏

规则6.1.1 用宏定义表达式时,要使用完备的括号。

说明:因为宏只是简单的代码替换,不会计算,存在一定的风险。

规则6.1.2 将宏定义的多条表达式放在大括号中。

说明:更好的方法是多条语句写成do while(0)的方式。

示例:

看下面的语句,只有宏的第一条表达式被执行。
#define FOO(x) \
    printf("arg is %d\n", x); \
    do_something_useful(x);

为了说明问题,下面for语句的书写稍不符规范
for (blah = 1; blah < 10; blah++)
FOO(blah)

用大括号定义的方式可以解决上面的问题:
#define FOO(x)    { \
                    printf("arg is %s\n", x); \
                    do_something_useful(x); \
                  }

但是如果有人这样调用:
if (condition == 1)
    FOO(10);
else
    FOO(20);

那么这个宏还是不能正常使用,所以必须这样定义才能避免各种问题:
#define FOO(x)      do{ \
                        printf("arg is %s\n", x); \
                        do_something_useful(x); \
                    }while(0)

用do-while(0)方式定义宏,完全不用担心使用者如何使用宏,也不用给使用者加什么约束。

规则6.1.3 使用宏时,不允许参数发生变化。

示例:

​​​​​​​如下用法可能导致错误。
#define  SQUARE(a) ((a)*(a))
int a=5;
int b;
b= SQUARE(a++);//结果:a=7,即执行了两次增。

正确用法:
b= SQUARE(a++);
a++;//结果:a=6,即执行了一次增。

同时也建议即使函数调用,也不要在参数中做变量变化操作,因为可能引用的接口函数,在某个版本升级后,变成了一个兼容老版本所做的一个宏,结果可能不可预知。

规则6.1.4 不允许直接使用魔鬼数字(没有具体含义的数字,字符串)。

说明:魔鬼数字含义不明确,维护难。使用常量定义魔鬼数字。0为特殊字符,没有歧义时,不用特别定义。

建议6.1.1 除非必要,应尽可能使用函数代替宏。

建议6.1.2 常量建议使用const定义代替宏。

建议6.1.3 宏定义中尽量不使用return、goto、continue、break等改变程序流程的语句。

建议6.1.4 常量后加后缀。32位常量要加ul。

U 或 u 无符号数

L 或 l 长整型

F 或 f 浮点数

第7章 数据类型

规则7.1.1 signed char和unsigned char用于数字型数据;char用于字符型数据。

说明:单纯的char所能接收的操作只有“ =、==、!= ”。

规则7.1.2 位域只能被定义为signed int和unsigned int。

说明:由于行为未被定义,所以不允许位域使用enum、short、char类型。

建议7.1.1 应使用指示了 大小 和 符号 的typedef以替代基本数据类型。

说明:不使用基本类型 char、int、short、long、float、double,而使用typedef创建别名体现大小和符号。

例如:32位计算机
typedef char                char_t;
typedef signed char         int8_t;
typedef unsigned char       uint8_t;
typedef signed short        int16_t;
typedef unsigned short      uint16_t;
typedef signed int          int32_t;
typedef unsigned int        uint32_t;
typedef signed long long    int64_t;
typedef unsigned long long  uint64_t;
typedef float               float32_t;
typedef double              float64_t;

附件1 常用单词缩写(英文)(元音:aeiou

全词

缩词/简写

中译

全词

缩词/简写

中译

指令内核相关类

source

src

源头

default

def

默认

destination

dst或des

目的地,目标

define

def

定义

operator

optr

操作符

macro

mcr

operand

opnd

操作数

return

ret

返回

offset

ofs

偏移

assemble

asm

汇编

clear

clr

清除

interrupt

intr

中断

move

mov

移动

priority

prio

优先级

instruction

instr

指令

vector

vect

向量

变量内存相关类

temperature

temper

温度

address

addr

地址

temporary

tmp

临时

pointer

ptr

指针

counter

ctr

计数器

buffer

buf

缓冲区

count

cnt

计数

stack

stk

flag

flg

旗帜、标识

memory

mem

内存

parameter

par

参数

storage

stg

存储器

argument

arg

参数

block

blk

variable

var

变量

allocate

alloc

分配

array

arr

数组

object

obj

对象

string

str

字符串

character

char

字符

数学计算相关类

increment

inc

增加

average

avg

平均数

decrease

dec

减少

summation

sum

求和;总和

addition

add

增加;加法

calculate

calc

计算

subtraction

sub

减少,减法

total

tot

总计

multiplication

mul

乘法

magnitude

mag

巨大

division

div

除法;除以

maximum

max

最大

proportion

kp

比例

minimum

min

最小

integral

ki

积分

middle

mid

中间

differential

kd

微分

equivalent

equiv

相等的

absolute

abs

绝对值

greater equal

ge

大于等于

algorithm

algo

算法

greater than

gt

大于

exponent

expo

指数

less equal

le

小于等于

recur

recu

递归

less than

lt

小于

limit

lim

限制

quarter

quar

四分之一

mantissa

mant

尾数

scale

scal

比例

fraction

fract

小数

double

dbl

两倍

digit

dig

数字

number

num

数字;数量

value

val

其他计算相关类

reference

ref

引用,参考

between

btw

之间

compare

cmp

比较

interval

intvl

间隔

different

diff

对比

different

diff

区别

optimization

opt

最优化

error

err

错误

degree

deg

度数,程度

exception

exc

异常

full

ful

全量

multiplex

mux

多路复用

result

rslt

结果

overflow

ovf

溢出

complete

comp

完成

check

chk

检查,核对

success

succ

成功

test

tst

测试

error

err

错误

detect

检测,识别

measure

meas

测量

sample

smp

样本

make

mk

制造

时间顺序相关类

timer

tmr或tim

定时器

new

新的

time

tm

时间

old

老的;旧的

second

sec

秒、第二

now

现在;目前

minute

min

分钟

current

cur

当前

hour

hr

小时

previous

prev

先前的

day

delay

dly

延迟

month

mth

expiration

expi

过期

year

next

nex

下一个

period

perd

时期

timestamp

ts

时间戳

timeout

to

超时

age

年龄

结构方向相关类

positon

pos

位置

origin

org

起源,原点

coordinates

coord

坐标系

point

pt

row

rect

rc

矩形

column

col

rectangle

rect

长方形

vertical

vert/v

垂直

cylinder

cyl

圆柱体

horizontal

hori/h

水平的

length

len

长度

dimension

dim

维度

high

hi

高度;高的

permutation

perm

排列

invert

invt

颠倒

信息相关类

information

info

信息

command

cmd

命令

communication

comu

通信

config

conf

配置

message

msg

消息;信息

request

req

请求

packet

pkt

信息包

acknowledge

ack

承认;应答

package

pkg

answer

ans

回答

protocol

proto

协议

response

rsp

响应

stream

stm

header

hdr

index

idx

索引

decode

deco

解码

frame

frm

帧率;框架

encode

enc

编码

clock

clok

时钟

coding

译码;编码

receive

recv

接收

authentication

auth

校验

send

send

发送

authentication code

authcode

校验码

context

ctx

上下文

unknown

unk

未知

connect

con

连接

extension

ext

扩展

ethernet

eth

以太网

expand

expa

扩展

mailbox

mbox

邮箱

field

fld

字段

mask

msk

掩码

identifier

id

标识符

decode

deco

解码

encode

enc

编码

计算机动作操作类

construct

cons

构建

select

sel

选择

control

ctl

控制

delete

del

删除

execute

exec

执行

insert

ins

插入

register

reg

注册

copy

cpy

复制

click

clk

点击

paste

粘贴

back

bk

后退

cut

剪切

disable

dis

使失效

print

Prn/prt

打印

enable

en

使能

input

in

输入

effective

eff

有效的

output

out

输出

invalid

inv

无效的

lock

lck

上锁

logic

lgc

逻辑的

unlock

unlk

解锁

read

r

scan

sca

扫描

write

w

search

srch

搜索

计算机专业名称类

iteration

itr

迭代;反复;重复

initialization

init

初始化

version

ver

版本

program

prg

程序

password

psw

密码

system

sys

系统

permission

perms

许可

android

adr

安卓操作系统

device

dev

设备

application

app

应用程序

administrator

adm

管理员

driver

drv

驱动

manager

mgr

管理者,管理器

update

upd

更新

standard

std

标准

upgrade

upg

升级

library

lib

静态库

environment

env

运行环境

database

db

数据库

process

proc

进程

dynamic

dyna

动态

ready

rdy

就绪

synchronization

sync

同步

suspend

susp

挂起

asynchronization

asyn

异步

status

sts

状态

link

lnk

链接

signal

sig

信号

server

svr

服务

semaphore

sem

信号量

executable file

exe

可执行文件

scheduler

scher

调度器

sequence

seq

序列

task

tsk

任务

serialize

seri

序列化

statistic

stat

统计

virus

vir

病毒

process

proc

进程

ready

rdy

就绪

文档图片类

directory

dir

目录

bitmap

bmp

位图纹理

list

lst

列表

image

img

图像

log

log

日志

picture

pic

图片

document

doc

文档

color

clr

颜色

text

txt

文本

record

rcd

记录

table

tab或tbl

表格

dictionary

dict

词典、字典

manual

man

手册

specification

spec

说明

软件界面名称类

screen

scr

屏幕

button

btn

按钮

display

disp

显示

component

com

组件(多用于ui组件目录命名)

util

工具

window

wnd

窗口

attribute

attr

属性

dialog

dlg

对话框

feature

fea

特征

cursor

csr

光标

bottom

btm

底部

markdown

md

文本标记语言

descriptor

desc

描述符

visible

vis

可见的

电气相关类

frequency

freq

频率

poweron

pwron

上电

voltage

vol

电压

back electromotive force

BEF

反电动势

current

cur

电流

speed

spd

速度

power

pwr

功率/电源

electric

elec

电子的

trigger

trig

触发器

threshold

thold

阈值

switch

sw

开关

toggle

tgl

切换

其他类

resource

res

资源

prefix

pre

前缀

region

rgn

区域、领域

reactive

react

有反应的

group

grp

recall

rcl

召回

assemble

asm

集合

release

rel

发布

repeat

rpt

重复

action

act

动作

duplicate

dup

重复

common

comm

通用

repository

repo

仓库

dependency

dep

依赖

reserve

resv

保留

debug

dbg

调试

reset

rst

重置

direct

dirt

直接的

resume

resu

重新开始

engine

eng

引擎

reverse

revs

反转

experiment

exp

实验

schedule

sch

计划

exposure

expo

曝光

section

sect

generate

gen

产生

segment

seg

handler

处理者

strategy

stra

策略

marshal

mar

序列化

change

chg

改变

unmarshal

unmar

反序列化

convert

conv

转换

deserialize

dese

反序列化

translate

tran

翻译,转换

manufacturer

mft

制造商

positive

posi

积极的

negative

neg

消极的

neutral

neut

中立

quality

qlty

质量

properties

prop

性能

performance

perf

性能

product

prod

产品

profile

pf

用户画像

project

proj

项目

protect

prot

保护

proxy

prx

代理

public

pub

公共的

附件2 常用反义词组(英文)

反义词

中译

反义词

中译

add

remove

添加/移除

min

max

最小/最大

add

delete

添加/删除

old

new

旧/新

begin

end

开始/最后

start

stop

开始/停止

create

destroy

创建/破坏

next

previous

下个/以前的

insert

delete

插入/删除

source

target

源头/目标

first

last

第一/最后

show

hide

显示/隐藏

get

release

获得/释放

send

receive

发送/接收

put

get

放下/获得

source

destination

源头/目的

increment

decrement

增加/减少

cut

paste

剪切/粘贴

lock

unlock

上锁/解锁

up

down

上/下

open

close

打开/关闭

top

btm

顶部/底部

附件3 Doxygen格式常用关键字表

Doxygen注释关键字更多内容详见Doxygen手册

注释命令

标签名

功能描述

特殊功能

\li

生成一个黑心圆.

-

              

生成一个黑心圆.                                                                                                            

-#

              

指定按顺序标记。                                                                                                           

::

              

指定连接函数功能。(注:空格和“:”有连接功能,但建议还是使用”::”。只对函数有用。)                                       

文件信息

@mainpage   

首页          

描述内容,并将注释提到首页标签中去                                                                                         

@copyright  

版权所有      

                                                                                                                           

@file       

              

文件名,可以默认为空,DoxyGen会自己加                                                                                      

@details

详细描述

@author     

作者          

                                                                                                                           

@version    

版本          

                                                                                                                           

@date       

日期          

                                                                                                                           

@remarks    

备注          

                                                                                                                           

@par        

自定义名      

开始一个段落,段落名称描述由你自己指定                                                                                     

@section    

自定义名

开始一个段落,段落名称描述由你自己指定                                                                                     

@name       

自定义名      

分组名强制给注释段给定自定义名称,自动列在注释前,比@brief还前。                                                           

@since {text}    

自从          

通常用来说明从什么版本、时间写此部分代码。                                                  

@todo { things to be done }     

待办事项:    

对将要做的事情进行注释,链接到所有TODO 汇总的TODO 列表                                                                                

模块信息

@include

包含文件

@var        

变量          

对模块 变量 进行标注,Doxygen会在该变量处产生一个链接,归纳到变量列表中去。                                                      

@typedef

对模块 变量类型 进行标注

@enum       

枚举          

对模块 枚举 进行标注,Doxygen会在该枚举处产生一个链接,归纳到枚举列表中去。                                                      

@struct     

结构体        

对模块 结构体 进行标注,Doxygen会在该枚举处产生一个链接,归纳到结构体列表中去。                                                  

@class      

类            

引用某个类 进行标注,格式:@class [] [] eg:@class CTest "inc/class.h"                              

@defgroup [gTag] [gName]

[gName]

定义模块组                                                                                                                  

@addtogroup [gTag]

  

添加到一个模块组                                                                                                      

@ingroup [gTag]  

  

加入到一个模块组                                                                                                         

@{          

              

模块开始                                                                                                                  

@}          

              

模块结束                                                                                                                  

@code       

              

在注释中开始说明一段代码,直到@endcode命令。                                                                              

@endcode    

              

在注释中代码段的结束。                                                                                                    

@pre { description of the precondition }

置条件  

用来说明代码项的前提条件。

@post { description of the postcondition }     

后置条件      

用来说明代码项之后的使用条件。                                                                                             

@relates

通常用来把非成员函数的注释文档包含在类的说明文档中。

函数信息

@fn

函数说明

@param      

参数          

主要用于函数说明中,后面接参数的名字,然后再接关于该参数的说明。标记一个参数的意义                                                           

@prg

列表说明参数信息

@return     

返回          

描述返回值情况eg: @return 本函数返回执行结果,若成功则返回TRUE,否则返回FLASE                                      

@retval     

返回值        

描述返回值类型 eg: @retval NULL 空字符串。@retval !NULL 非空字符串                                                         

@note       

注解          

开始一个段落,用来描述一些注意事项                                                                                                                          

提醒信息

@brief      

              

概要信息,简短描述,自动列在注释前。                                                                                        

@see {comment with reference to other items }         

参见          

一段包含其他部分引用的注释,中间包含对其他代码项的标识符,自动产生对其标识符的引用链接。                                       

@attention  

注意          

                                                                                                                           

@bug        

Bug:         

缺陷,链接到所有缺陷汇总的缺陷列表                                                                           

@warning {warning message }

警告          

一些需要注意的事情     

@sa

参考资料

@exception {exception description}

异常          

可能产生的异常描述 eg: @exception 本函数执行可能会产生超出范围的异常                                                       

@deprecated

弃用:        

已废弃函数,链接到 待办事项列表                                             

附件4 标识符命名个人风格

标识符命名个人风格

标识符

其他环境

FreeRTOS环境

uCos-II环境

文件夹名

帕斯卡(大驼峰)

帕斯卡(大驼峰)

帕斯卡(大驼峰)

文件名

下划线

下划线

下划线

变量名

骆驼(小驼峰)

静态变量加前缀s_
全局变量加前缀g_
类的数据成员加前缀m_

结构体变量加前缀st_

联合体变量加前缀ut_

枚举变量加前缀et_

匈牙利 (有修改)
标识符名:类型+对象描述
类型:
uint32_t对应前缀ul
uint16_t对应前缀us
uint8_t对应前缀uc
char(仅用于字符)对应前缀c
枚举类型对应e
指针类型对应p
其他类型对应x
char *对应前缀pc

下划线

常量/宏名

全大写

小写(文件名部分)+大写
例:configUSE_PRE

全大写

函数名

帕斯卡(大驼峰)
谓-宾(动-名)结构

匈牙利 (有修改)
static限定函数对应前缀prv(私有)
API函数返回值类型为函数名前缀
API函数名使用所在的文件名,例如在tasks.c文件中函数 vTaskDelete();

帕斯卡(大驼峰)
程序类别作为前缀
OS_TaskIdle( )

方法名

帕斯卡(大驼峰)

接口名

帕斯卡(大驼峰)

类名

帕斯卡(大驼峰)
以C开头

结构体类型名

帕斯卡(大驼峰)
以S开头

联合体类型名

帕斯卡(大驼峰)
以U开头

枚举类型名

帕斯卡(大驼峰)
以E开头
枚举值同 常量/宏名

附件5 常见标识符命名风格种类

常见 编程标识符命名风格 种类

类别

别称

命名法逻辑 特点

举例

优缺点

常见应用场合

帕斯卡

大驼峰

大小写混排,每个单词的首字母大写。

void GetKey(void);
int TimeCount;

函数库和Jave平台下居多。

骆驼

小驼峰

大小写混排,每个单词的首字母大写,第一个单词的首字母小写。

void getKey(void);
int timeCount;

面向对象语言(Java、C#)变量、方法常用。
事实上,很多程序员在实际命名时将骆驼命名法和帕斯卡命名结合使用。例如:变量用骆驼命名法;函数用帕斯卡命名法。

匈牙利

类同
小驼峰

大小写混排,每个单词的首字母大写,第一个单词的首字母小写,小写字母用来表明标识符的属性、类型等。

标识符名:属性+类型+对象描述。
属性:g_ 全局变量;c_ 常量;m_ c++类成员变量;s_ 静态变量
类型:a数组;p指针;v无返回值;fn函数;h句柄;u无符号;
      b布尔;c字符;i整型;l长整型;f浮点型;n短整型;
      d双精度浮点;r实型;w字;dw双字;by字节;sz字符串;
描述:Max最大;Min最小;Init初始化;Temp临时变量;
      Src源对象;Dest目的对象。 

void vGetKey(void);
int g_iTimeCount;

优点:可读性很强,清晰。
缺点:变更变量类型和属性麻烦;C++是强类型,体现不出优点。随着编译器的优化,优点也在被弱化。此法争议多。

非Windows系统开发,笔者不建议使用匈牙利法,可扬长去短,保留:g_全局变量,m_成员变量,s_静态变量。

常见于Windows。

下划线

全小写,以 下划线 分割逻辑断点。上面是以大写字母为逻辑断点。

void get_key(void);
int time_count;

常见于Linux内核,C++标准库,Boost以及Ruby,Rust等语言。C、Python变量常用。

你可能感兴趣的:(规范,代码风格,软件编程规范,代码编程规范)