1、总体原则
1.1、代码以人为本
编写程序应该以人为本,计算机第二。代码首先是给人读的,好的代码应当可以像文章一样通顺易读。遵循以下原则:
- 不使用单词缩写、不使用汉语拼音
- 良好的命名规则
- 尽量不使用跨文件的全局变量
- 废弃的代码要及时清除
- 重复代码应该尽可能提炼成函数,避免出现过长的函数
- 文件职责单一化
- 一个函数仅完成一个功能
1、文件与目录
原则:嵌入式代码每个.c文件必须包含一个.h文件。函数的定义应在相应的.c文件中,声明在相应的.h文件中。
1.1、 对于源码文件中的段落安排
我们建议按如下的顺序排列:
- 文件头注释
- 防止重复引用头文件的设置
- #include 部分
- #define 部分
- enum 常量声明
- 类型声明和定义,包括 struct、union、typedef 等
- 全局变量声明
- 文件级变量声明
- 全局或文件级函数声明
- 函数实现。按函数声明的顺序排列
- 文件尾注释
1.2、在引用头文件时,使用 <> 来引用预定义或者特定目录的头文件,使用 “” 来引用当前目录或者路径相对于当前目录的头文件。
#include <stdio.h> /* 标准头文件 */
#include <projdefs.h> /* 工程指定目录头文件 */
#include “global.h” /* 当前目录头文件 */
#include “inc/config.h” /* 路径相对于当前目录的头文件 */
1.3、 为了防止头文件被重复引用,应当用 ifndef/define/endif 结构产生预处理块。
#ifndef __DISP_H /* 文件名前名加两个下划线“__”,后面加 “_H”*/
#define __DISP_H
//用户代码
#endif
1.4、头文件中只存放“声明”而不存放“定义”,通过这种方式可以避免重复定义。
/* 模块 1 头文件: module1.h */
extern uint8_t g_ucPara; /* 在模块 1 的 .h 文件中声明变量 */
/* 模块 1 实现文件:module1.c */
uint8_t g_ucPara = 5; /* 在模块 1 的 .c 文件中定义全局变量 g_ucPara */
2、代码注释
2.1、总体注释要求
- 注释语言必须准确、易懂、简洁;
- 修改代码同时修改相应的注释, 以保证注释与代码的一致性,不再有用的注释要删除;
- 建议多使用中文,除非能用非常流利准确的英文表达。
- 采用中文注释时采用GB2312编码方式进行编码。
- 优秀的代码可以自我解释,不通过注释即可轻易读懂。
- 注释应与其描述的代码靠近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。
- 注释与所描述内容进行同样的缩排。
2.2、源文件头部的注释
/*==========================================================================================================================
// Copyright @ 公司名称,2018-2020,项目
// @文件名称: (文件名)
// @文件说明: (用于详细说明此程序文件完成的主要功能,与其他模块或函数的接口,输出值、取值范围、含义及参数间的控制、顺序、独立或依赖等关系)
//--------------------------------------------------------------------------------------------------------------------------
// @硬件平台: 芯片型号
// @软件平台: 软件型号
//--------------------------------------------------------------------------------------------------------------------------
// 版本号 日期 作者 说明
============================================================================================================================*/
2.3、函数头部的注释
/*==========================================================================================================================
// @函数名称:
// @函数描述:
//--------------------------------------------------------------------------------------------------------------------------
// @参数值:
// 输入参数:
// 输出参数:
// @返回值:
============================================================================================================================*/
2.4、块注释
开头: /*
结尾: */
例:
/*
* ... This is a block comment ...
*/
2.5 行注释
开头: //
例:
// This is a line comment...
3、命名规则
3.1、总体命名要求
- 所有命名都应使用标准的英文单词或缩写,最好不使用拼音或拼音缩写,除非该名字描述的是中文特有的内容,如半角、全角, 声母、韵母等。
- 所有命名都应遵循达意原则,即名称应含义清晰、明确。
- 所有命名都应该完整的反应具体的功能。
- 所有命名都应尽量使用全称。
3.2、文件命名规则
- 用户编写的文件命名统一采用小写字符+下划线的方式。
实例:task_app_diagnostic.c task_app_diagnostic.h - 文件名要与模块名对应。
3.3、函数命名规则
3.3.1、普通函数
- 函数命名应以函数要执行的动作命名,一般采用动词或者动词+名词的结构
- 函数命名使用驼峰命名法,一个文件的内部使用static关键字限制函数作用域。
//文件内部函数
static int16_t Service0x10Process(uint8_t *udsData, uint16_t udsLen, uint8_t functionAddressFlag)
//文件外部函数
void TaskEcuDiagnostic(void *pvParameters)
- 函数参数尽量保持顺序从左到右为:输入、修改、输出。
3.3.2、指针函数
- 采用*p+驼峰命名法
typedef int16_t (*pServiceFunction)(uint8_t *udsData, uint16_t udsLen, uint8_t functionAddressFlag);
3.4、宏命名规则
- 宏定义全部使用大写,两个单词之间用下划线隔开。
- 除了头文件或编译开关等特殊标识定义,宏定义不能使用下划线“_”开头和结尾
- 用宏定义表达式时,要使用完备的括号
- 将宏定义的多条表达式放在大括号中,更好的方法是多条语句写成do while(0)的方式。
- 使用宏时,不允许参数发生变化
- 尽量使用函数代替宏表达式
- 常量建议使用const定义代替宏
3.5、变量类型
尽量使用全称等
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
#define __IO volatile
3.6、变量命名
- 局部变量采用小驼峰命名法,即第一个单词小写,第二个单词首字母大写
uint8_t negativeNum = 0;
- 跨文件的全局变量在小驼峰命名法加前缀’g_’
uint8_t g_negativeNum = 0;
- 本文件的全局变量在小驼峰命名法加前缀’m_’
uint8_t m_negativeNum = 0;
- 静态变量在小驼峰命名法增加“s_”前缀。
static uint8_t sNegativeNum = 0;
- 指针变量加“p_”
- 除了通用的缩写以外,不得使用单词缩写,不得使用汉语拼音
3.7、类型命名
3.7.1、结构体类型
- 采用str_+大驼峰式命名法_TypeDef,成员变量采用小驼峰命名法
typedef struct
{
unsigned char studentName;
unsigned char studentAge;
......
}str_StudentTypeDef,*str_pStudentTypeDef;
str_StudentTypeDef str_Student;
3.7.2、枚举类型
- 采用enum_+大驼峰式命名法_TypeDef,成员变量采用小驼峰命名法
typedef enum
{
securityTimerNone,
securityTimerResetDelay,
......
}enum_SecurityTimerTypeDef;
enum_SecurityTimerTypeDef m_securityTimer;
4、排版布局
4.1、头文件排版布局
头文件排版内容依次为包含的头文件、宏定义、类型定义、声明变量、声明函数。且各个种类的内容间空三行。