目 次
目次. I
前言. II
1 规范制定说明. 1
2 适用范围. 1
3 基本原则. 1
4 组织构成及排版要求. 1
4.1组织构成及包含内容. 1
4.2 文件书写的层次. 1
4.3 排版要求. 2
5 注释. 3
5.1文件头和函数头. 3
5.2 注释. 4
6 命名规则. 5
6.1 命名规则总则. 5
6.2 变量命名规则. 6
6.3文件及函数命名. 7
6.4新定义的类型命名规范. 7
7 变量、常量、宏定义与类型. 7
8.指针和数组、结构与联合. 8
9 初始化、声明和定义. 9
9.1初始化. 9
9.2声明和定义. 9
10 控制语句和表达式. 10
11 函数. 10
12 预处理指令. 11
13 其余规则. 11
前 言
为提高产品代码质量,指导嵌入式软件开发人员编写出简洁、可维护、可靠、可测试、高效、可移植的代码,避开危险的编程方式,编写了本规范。
本标准由XX公司 XX部提出。
本标准由XX公司 XX部归口。
本标准起草单位:
本标准主要起草人:
本标准主要修改人:
参考《MISRA 2004编码规则》。
编制 |
校对 |
审核 |
标准 |
批准 |
批准日期 |
XX |
XX |
嵌入式编程手写C代码编码规范
1 规范制定说明
本规范制定的意义在于提高代码的可读性,使代码标准化,为代码的集成、测试、维护、审查提供便利。
本规范作用在于约束代码编写规则,宗旨是使得代码简洁明了,可读性及可移植性强、易于维护。
本规范给出嵌入式软件C语言编码格式要求,并从排版要求、注释要求、命名规则、变量常量宏定义及类型、初始化、声明及定义、控制语句与表达式等方面详细给出编码规则,便于C语言编码人员及代码静态测试人员使用。
2 适用范围
本规范适用于XX公司嵌入式编程手写C代码开发,如VCU控制器手写代码部分的开发。
3 基本原则
1)代码简洁、语句清晰,风格统一。
2)注释清晰明了,便于阅读。
3)代码结构清晰,可读性强,便于维护与测试。
4)模块化编程,尽量少用全局变量,避免使用GOTO语句。
5)通俗易懂不产生歧义。
4 组织构成及排版要求
4.1组织构成及包含内容
嵌入式代码源代码中包含头文件(.h)及源文件(.c),包含的内容为:
1)头文件:文件头说明、提供给外部参考的类型、常量、宏定义、(全局)函数声明、全局变量的原型声明,不要定义变量。
2)源文件:文件头说明、函数头说明、只在本文件中使用的类型、常量、宏定义及全局变量和文件级(static)变量定义。
4.2 文件书写的层次
1)实现文件(.C文件)的层次:
文件头
#include (依次为标准库头文件,非标准库头文件)
文件内部常量定义
文件内部宏定义
文件内部数据类型
文件内部静态全局变量
函数原型定义
2)声明文件(.H文件)的层次:
文件头
#ifndef _文件名_H (全大写)
#define _文件名_H (全大写)
其他条件编译选项
#include (依次为标准库头文件,非标准库头文件)
全局常量声明
全局宏声明
全局数据类型声明
全局变量声明
外部引用
全局函数原型声明
#endif /* _文件名_H */
注意事项:
- 头文件尽量通过宏定义避免重复包含。
- 包含标准库头文件使用尖括号“<>”,包含非标准库头文件使用双引号“” ””。
4.3 排版要求
- 程序块采用缩进风格编写,缩进的空格数为4个,缩进采用空格键,不使用tab键。
- 相对独立的程序块之间、变量说明后必须加空行。
- 代码行不宜过长,较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。
eg:act_task_table[taskno].duration_true_or_false
= SYS_get_sccp_statistic_state( stat_item );
- 若函数或过程中的参数较长,则要进行适当的划分。函数调用和函数声明续行在第一个参数处对齐,类型与名称不能分行书写。
eg:
n7stat_flash_act_duration( stat_item, frame_id *STAT_TASK_CHECK_NUMBER
+ index, stat_object );
- 在函数体的开始、结构体的定义、联合体的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用程序块的分节符“{”“}”,分节符应独占一行且位于同一列,同时与引用它的语句左对齐。
- if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要加括号{}。
eg:
如下例子不符合规范。
if (pUserCR == NULL) return;
应写作:
if (pUserCR == NULL)
{
return;
}
- do while使用时,while不独占一行。
- 定义指针类型变量时,*放在变量名前。
- 一行只允许写一个声明或一条语句。
eg:
= 0; = 0;
应写作:
= 0;
= 0;
- 在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如->),后不应加空格。
- 逗号、分号只在后面加空格。
eg:
int a, b, c;
- 比较操作符, 赋值操作符"="、 "+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位域操作符"<<"、"^"等双目操作符的前后加空格。
eg:
if (current_time >= MAX_TIME_VALUE)
a = b + c;
a *= 2;
a = b ^ 2;
- "!"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。
eg:
*p = 'a'; // 内容操作"*"与内容之间
flag = !isEmpty; // 非操作"!"与内容之间
p = &mem; // 地址操作"&" 与内容之间
i++; // "++","--"与内容之间
- "->"、"."前后不加空格。
eg:
p->id = pid; // "->"指针前后不加空格
- if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。
eg:
if (a >= b && c > d)
5 注释
5.1文件头和函数头
- 源文件(包括说明性如:头文件.h文件、.inc文件、.def文件、编译说明文件.cfg等)头部应放置注释文字,注释必须列出:版权说明、版本号、完成日期、作者、内容、模块目的/功能、主要函数及其功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明。
可参照如下源文件头注释,但是不局限于此。
/************************************************
File Name:BCU_TLE8104E_Drive.c
Author: yangdan
Version: v1.00.0002
Comment: TLE8104E应用相关的程序。
Function List :
1.————
History:
v1.00.0000 20171021 初始版本
************************************************/
- 函数头部也应进行注释,注释时要列出:函数名、函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)等(必要时要举例说明函数的使用方法)。可参照如下函数头进行注释,但不局限于此。
/***************************************************************
Function: Std_ReturnType QSPI2_ReadWriteData_TLE8104E(Spi_DataType *TxDataBufferPtr,Spi_DataType *RxDataBufferPtr,Spi_SequenceType SpiConf_SpiSequence,Spi_NumberOfDataType Length)
Description: QSPI读写函数
Input: Spi_DataType* TxDataBufferPtr----发送的数据
Spi_DataType* RxDataBufferPtr----接收的数据
Spi_SequenceType SpiConf_SpiSequence----QSPI队列
Spi_NumberOfDataType ui8_DataLength----发送接收的数据长度
Output:
Return: E_OK/E_NOT_OK
Time:
Other: QSPI2_ReadWriteData_TLE8104E(tx_buff,rx_buff,SpiConf_SpiSequence_TLE8104E[TLE8104E_ChipId],1)
***********************************************************************/
5.2 注释
- 注释率要求>20%。
- 注释的内容要清楚明了、含义准确,防止注释二义性。
- 注释中避免使用缩写。
- 对单条语句的注释应放在其上方或右方相邻位置,如放于上方则需与其上面的代码用空行隔开。
- 对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其物理含义。变量、常量、宏的注释应放在其上方相邻位置或右方。
- 数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释放在此域的右方;可按如下形式说明枚举/数据/联合结构。
/* sccp interface with sccp user primitive message name */
enum SCCP_USER_PRIMITIVE
{
N_UNITDATA_IND, /* sccp notify sccp user unit data come */
N_NOTICE_IND, /* sccp notify user the No.7 network can not */
/* transmission this message */
N_UNITDATA_REQ, /* sccp user's unit data transmission request*/
};
- 全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明。
- 分支语句(条件分支、循环语句等)必须编写注释。
- 对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释。
- 注释格式尽量统一,建议使用“/*……*/”。
- 注释与对应代码采用同样缩进。
6 命名规则
6.1 命名规则总则
- 标识符(内部的和外部的)的有效字符不能多于31。
- 程序中不要出现仅靠大小写区分的相似变量名;局部变量不应与全局变量标识符使用相同的名称。
eg:
uint8 test;
{
uint8 test; /*定义了两个test */
test = 3; /*这将产生混淆 */
}
- 具有静态存储期的对象或函数标识符不能重用。
eg:
/* 定义了一个静态文件域变量test1 */
static uint8 test1;
uint8 test1; /**在另一个文件又定义了一个具有外部链接的文件域变量test1*/
- 标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。
eg:
好的命名方法:
uint16 DebugMessage;
uint8 ErrNum;
不好的命名方法:
uint16 dbmesg;
uint8 en;
- 常见通用的单词缩写尽量统一,只能使用英语。
说明:对于特定的项目要使用的专有缩写应该注明或者做统一说明。
- 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。
- 标示符尽量避免使用数字编号,除非逻辑上需要。
eg:
#define DEBUG_0_MSG
#define DEBUG_1_MSG
应改为更有意义的定义:
#define DEBUG_WARN_MSG
#define DEBUG_ERR_MSG
- 不要使用单个字符(如i, j, k…)作为标示符,但i, j, k作局部循环变量是允许的。
- 不单独使用小写字母“l”或大写字母“O”作为变量名。
6.2 变量命名规则
- 全局变量添加”G _”前缀,全局静态变量添加” S_ ”,局部静态变量添加”s_”前缀,局部变量无前缀。使用一致的小写类型指示符作为前缀来区分变量类型,如下表。全局变量格式:前缀_变量类型_模块名称_变量名称,变量名称部分太长可用“_”分开。表示模块的缩写词全部大写,变量类型简称见表1。
eg:
s_s16_EEPROM_ErrorNum;
S_u8_InSignal_PWMFlag;
G_s16_OS_TimerOneStartReadyFlag_receive
表 1 变量类型的简称
原始类型 |
定义类型 |
解释 |
缩写 |
|
signed char |
sint8 |
有符号字符型8 bit |
s8 |
|
unsigned char |
uint8 |
无符号字符型8 bit |
u8 |
|
signed short |
sint16 |
有符号短整型16 bit |
s16 |
|
unsigned short |
uint16 |
无符号短整型16 bit |
u16 |
|
signed int |
sint32 |
有符号整型32 bit |
s32 |
|
unsigned int |
uint32 |
无符号整型32 bit |
u32 |
|
float |
float32 |
浮点型32 bit |
f32 |
|
double |
float64 |
双精度 64bit |
f64 |
|
unsigned long |
uint32 |
无符号长整型32 bit |
ult32 |
|
unsigned long |
uint64 |
无符号长整型64 bit |
ult64 |
|
signed long |
int32 |
有符号长整型32 bit |
slt32 |
|
signed long |
int64 |
有符号长整型64 bit |
slt64 |
|
unsigned char |
boolean |
布尔类型TRUE/FALSE |
bool |
- 局部变量格式:变量类型_变量名称,变量名称部分若太长可用“_”分开。大小写规则与全局变量相同。
eg:
uint8 u8_ InBusCANFlag_return
- 定义指针变量*紧挨变量名,全局指针变量使用大写P前缀”P_”,局部指针变量使用小写p前缀”p _”。
eg:
uint32 *P_MsgAddress; /*全局变量*/
uint8 *p_msg; /*局部变量*/
- 常量(#define定义的常量、枚举、const定义的常量)的定义使用全大写字母,格式:模块名_名称,名称部分太长可用“_”分开。
eg:
#define MATH_PI 3.14
const double MATH_PI = 3.14;
enum weekday{ SUN,MON,TUE,WED,THU,FRI,SAT };
- 常数宏定义时,十六进制数的表示方法为0xFF。
说明:前面0x中的x小写,数据中的”A-F”大写。
6.3文件及函数命名
- 文件名应为“模块+功能”,首字母大写分开组合单词,若有必要可使用“_”分隔符,模块名简称需大写。
需要完整文档点击如下链接下载:
百度MCU嵌入式C代码编码规范资源-****文库