命名规范与注释规范概述

概述

本文根据自己的日常代码书写习惯,整理一下关于C语言编码过程中的命名规范和注释规范。每个人有自己的编程习惯,本文仅供参考,不作为标准。

正文

由于本人学习安富莱的教材,感觉其编码规范做得很好,所以我们参考安富莱的命名规范来学习。

1、文件与目录

文件命名

文件的命名需要准确清晰,适当使用字母缩写,使得名字精简。如:App.cUart.c等。

头文件中段落安排顺序

1、文件头注释
2、防止重复引用头文件的设置
3、#include部分
4、enum常量声明
5、类型声明和定义,包括struct、union、typedef等
6、全局变量声明
7、文件级变量声明
8、全局或文件级函数声明
9、函数实现。按函数声明的顺序排序
10、文件尾注释

在引用头文件时,不要使用绝对路径

#include “/project/inc/hello.h” //不应使用绝对路径
#include “…/inc/hello.h” //可以使用相对路径

在引用头文件时,使用<>还是“”

#include <stdio.h> //标准头文件
#include <projdefs.h> //工程指定目录头文件
#include “global.h” //当前目录头文件
#include “inc/config.h” //路径相对于当前目录的头文件

防止头文件被重复引用

#ifndef __DISP_H //文件名前加两个下划线,后面加_H
#define __DISP_H


#endif

头文件中只存放“声明”而不存放“定义”

/* 模块1头文件:module1.h */
extern int a = 5; //在模块1的.h文件中声明变量

文件的长度

文件的长度没有非常严格的要求,但应尽量避免文件过长。一般来说,文件长度应尽量保持在1000行以内。

2、排版

(1)程序块要采用缩进风格编写,缩进的空格数为4个。
(2)相对独立的程序块之间、变量说明之后必须加空行。

在这里插入图片描述

(3)较长的语句或函数过程参数(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。

在这里插入图片描述

(4)不允许把多个短语句写在一行中,即一行只写一条语句。

在这里插入图片描述

(5)程序块的分界符(如大括号)应各独占一行并且位于同一列。

在这里插入图片描述

(6)在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如- >),后不应加空格。
  • 逗号、分号只在后面加空格
uint32_t a, b, c;
  • 比较操作符,赋值操作符“=”、“+=”,算术操作符“+”、“%”,逻辑操作符“&&”、“&”,位域操作符“<<”、“^”等双目操作符的前后加空格。
if (current_time >= MAX_TIME_VALUE)
{
    
    
	a = b + c;
	a *= 2;
	a = b ^ 2;
}
  • “!”、“~”、“++”、“-”、“&”(地址运算符)等单目操作符前后不加空格。
*p = 'a';		
flag = !isEmpty;
p = &mem;
i++;
  • “->”、“.”前后不加空格。
p->id = pid;
  • if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显,函数名与其后的括号之间不加空格,以与保留字区别开。
if (a >= b && c > d)

3、注释

常见在函数、模块的头部注释或者同行注释。
常见的注释说明如下:

@brief 函数、模块功能简要说明
@remark 特殊说明
@param[in] 输入参数
@param[out] 输出参数
@return 返回类型
@retval 返回值

4、可读性

(1)注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级。
/*正确的写法*/
word = (high << 8) | low;
if ((a | b) && (a & c))
if ((a | b) < (c & d))

/*错误的写法*/
word = high << 8 | low;
if (a | b && a & c)
if (a | b < c & d)		//造成了判断条件出错
(2)避免使用不易理解的数字,用有意义的标识来替代。
/*不规范写法*/
if (Trunk[index].trunk_state == 0)	//<---不规范写法,应使用有意义的标识
{
    
    
	Trunk[index].trunk_state = 1;	//<---不规范写法,应使用有意义的标识
}

/*规范写法*/
if (Trunk[index].trunk_state == TRUNK_IDLE)
{
    
    
	Trunk[index].trunk_state = TRUNK_BUSY;
}
(3)不要使用难懂的技巧性很高的语句,除非很有必要时。

说明:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。
示例:如下表达式,考虑不周就可能出问题,也较难理解。

/*不规范代码*/
* stat_poi ++ += 1;
* ++ stat_poi += 1;

/*规范代码*/
*stat_poi += 1;
stat_poi++;		//此二语句功能相当于“* stat_poi ++ += 1;”

++ stat_poi;
*stat_poi += 1;	//此二语句功能相当于“* ++ stat_poi += 1;”

5、变量、结构、常量、宏

(1)为方便书写及记忆,变量类型采用如下重定义:

在这里插入图片描述

(2)常见类型的前缀
  • 对于一些常见类型的变量,应在其名字前标注表示其类型的前缀。前缀用小写字母表示。前缀的使用请参照下列表格中说明。

在这里插入图片描述

(3)变量作用域的前缀

为了清晰的标识变量的作用域,减少发生命名冲突,应该在变量类型前缀之前再加上表示变量作用域的前缀,并在变量类型前缀和变量作用域前缀之间用下划线隔开。
具体的规则如下:

  • 对于全局变量(global variable),在其名称前加g和变量类型符号前缀。
uint32_t g_ulParaaWord;
uint8_t g_ucByte;
  • 对于静态变量(static variable),在其名称前加s和变量类型符号前缀。
static uint32_t s_ulParaWord;
static uint8_t s_ucByte;
  • 函数内部等局部变量前不加作用域前缀
  • 对于常量,当可能发生作用域和名字冲突问题时,以上几条规则对于常量同样适用。注意,虽然常量名的核心部分全部大写,但此时常量的前缀仍然用小写字母,以保持前缀的一致性。
(4)结构体命名规则

表示类型的名字,所有名字以小写字母tag开头,之后每个英文单词的第一个字母大写(包括第一个单词的第一个字母),其他字母小写,结尾T标识。单词之间不使用下划线分隔,结构体变量以t开头。如:

typedef struct tagBillQuery_T
{
    
    
...
}BillQuery_T;
/*结构体变量定义*/
BillQuery_T tBillQuery;
(5)对于枚举定义全部采用大写,结尾_E标识。
typedef enum
{
    
    
	KB_F1 = 0,		//F1键代码
	KB_F2,			//F2键代码
	KB_F3			//F3键代码
}KEY_CODE_E;
(6)常量、宏、模版的名字应该全部大写。如果这些名字由多个单词组成,则单词之间用下划线分隔。
#define LOG_BUF_SIZE 	8000

6、函数

(1)函数的命名规则

每一个函数名前缀需包含模块名,模块名为小写,与函数名区别开。

如:uartReceive(串口接收)

备注:对于非常简单的程序,可以不加模块名。

(2)函数的形参

函数的形参都以下划线开头,已示与普通变量进行区分,对于没有形参为空的函数(void)括号紧跟函数后面。

(3)一个函数仅完成一件功能。
(4)函数名应准确描述函数的功能,使用动宾词组为执行某操作的函数命名。

说明:避免用含义不清的动词如processhandle等为函数命名,因为这些动词并没有说明要具体做什么。
示例:参照如下方式命名函数。

void PrintRecord(uint32_t _RecInd);
int32_t InputRecord(void);
uint8_t GetCurrentColor(void);
(5)避免设计五个以上参数函数,不使用的参数从接口中去掉。

说明:目的减少函数间接口的复杂度,复杂的参数可以使用结构传递。

(6)在调用函数填写参数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换。

说明:因为数据类型转换或多或少存在危险。

(7)防止把没有关联的语句放到一个函数中。

示例:如下函数就是一种随机内聚。

void InitVar(void)
{
    
    
	Rect.length = 0;
	Rect.width = 0;		//初始化矩形的长与宽
	
	Point.x = 10;
	Point.y = 10;		//初始化“点”的坐标
}

矩形的长、宽与点的坐标基本没有任何关系,故以上函数是随机内聚。应如下分为两个函数:

void InitRect(void)
{
    
    
	Rect.length = 0;
	Rect.width = 0;		//初始化矩形的长与宽
}

void InitPoint(void)
{
    
    
	Point.x = 10;
	Point.y = 10;		//初始化“点”的坐标
}

参考

  • 安富莱电子论坛

猜你喜欢

转载自blog.csdn.net/SammySum/article/details/120660625