嵌入式开发C语言编程规范

前言

不定时更新入职嵌入式岗位后公司要求的编程规范


一 代码总体原则

1、清晰第一
清晰性是易于维护、重构程序必需具备的特征。

2、简洁为美
简洁就是易于理解、实现并具有高可靠性。

二 头文件

1、头文件应尽可能少包含/依赖其他头文件
接口声明与包含头文件过于复杂会导致编译时间过长。
.c/.h文件禁止包含用不到的头文件。

2、头文件中放置接口的声明,不能放置实现
每个.c文件应有一个同名.h文件,用于声明需对外公开的接口。
只能通过包含.h文件的方式使用其他.c文件提供的接口,禁止在.c中extern使用外部接口。

3、头文件应向稳定的方向包含
不稳定的模块包含稳定的模块。产品依赖于平台,平台依赖于标准库。
包含头文件顺序,从上到下:业务模块->功能模块->平台模块->标准模块。
禁止头文件循环包含/依赖。

4、头文件#define定义宏,防止头文件被多次包含
为了保证宏的唯一性,较好的命名方式是PROJECTNAME_PATH_FILENAME_H。不能在受保护部分的前后编写代码。
示例:假定9270_TEST工程的VehicleMounted模块的VehicleMounted.h,其目录为9270_TEST/VehicleMounted/VehicleMounted.h,应按如下方式保护:
#ifndef 9270_TEST_VehicleMounted_VehicleMounted_H
#define 9270_TEST_VehicleMounted_VehicleMounted_H
…(编写头文件代码)
#endif

5、禁止在extern ”C”中包含头文件
否则会破坏头文件原意,错误更改头文件接口函数编译链接规范。

三 函数

1、一个功能函数仅实现一种功能
主流程/骨干函数函数可以是单一函数完成。
一个功能函数尽可能具有通用性。
一般一个功能函数不能超过50-70行代码。
一个函数尽可能不要依赖另一个函数去完成功能。
一个函数内代码块嵌套不超过4层。

2、冗余代码考虑提炼成函数。
编写函数时,逻辑与数据要分开。
没有被调用的变量与函数要及时清除。

3、可重入函数不可使用共享变量
若必须使用共享变量,应利用互斥手段(信号量、中断)进行保护。

4、检查参数合法性由调用者还是接口函数完成,项目组应统一规定
避免两者都进行参数的合法性检查,产生冗余代码。
接口函数内应对全局变量、数据文件等非参数输入进行有效性的检查。

5、函数提供了指示错误方法,在调用完该函数返回时应立刻检查错误指示

6、要设计高扇入(函数被调用),合理扇出的函数
不能为了高扇入而把不相关的功能凑成一个模块,使模块内聚程度较低。

7、函数参数不超过5个
不变参数使用const修饰。
除打印类函数外,避免使用可变长参数函数。

8、内部函数应该增加static关键字
声明源文件内可用,避免与其他文件或库中的相同标识符发生混淆。

9、函数内谨慎使用全局变量、静态局部变量和IO操作
使用时需考虑函数可重入、函数功能可预测,以及IO操作混乱。

10、函数命名风格项目组内部应保持统一

四 标识符命名与定义

1、标识符的命名应清晰易理解
除了常见单词缩写外,不使用缩写,禁止使用汉字拼音。
具有互斥意义的变量或函数应使用正确的反义词组命名。
除非逻辑上需要,避免命名中出现数字编号。

2、命名风格项目组内部应保持统一
宏:单词全大写,单词用_隔开。
函数:模块名_谓语动词_宾语。全小写(模块名除外)。
变量:名词/形容词_名词。全小写,不应出现谓语动词。
指针:加前缀p/p_单词。全小写。
枚举:单词首字母全大写,类型定义尾缀加_E。
结构体:单词首字母全大写,类型定义尾缀加_ST/_T。
文件名:主模块_从模块_功能名。不同系统对文件名的单词大小写处理会有不同(Windows系统不区分大小写,Linux系统区分),所以建议文件名全小写。

3、修改代码应与原有代码命名风格保持一致

五 变量

1、一个变量只有一个功能用途
禁止使用未初始化的变量作为右值。
建议定义变量时就将其初始化。

2、设计结构仅明确描述一个对象,不应把无关联的描述元素放入同一结构中
在跨平台的通讯过程中,注意使用的结构字节序的转换。

3、全局变量必须加static关键字,尽量少用全局变量
避免定义同名的全局变量与局部变量。
建议仅有一个模块或函数可以定义或改变全局变量,其他模块或函数只能访问全局变量。

4、面向接口编程思想,通过接口函数对外提供数据的访问

六 宏、常量

1、宏定义一条表达式,注意加括号
如求面积宏:#define AREA(x, y) ((x) * (y))

2、宏定义多条表达式,写成do-while(0)的方式
如两数交换:#define SWAP(x, y) do {
(x) = ((x) + (y));
(y) = ((x) - (y));
(x) = ((x) - (y));
}while(0)

3、宏定义中谨慎使用return等改变流程的语句,容易引起内存泄露问题

4、使用宏时,禁止在参数中做变量变化操作
如求立方数:#define CUBE(x) ((x) * (x) * (x))
cube_x = CUBE(x++);//导致x自增三次

5、禁止直接使用意义不明的数字
局部使用可定义const局部变量。广泛使用必须定义const全局变量/宏。
常量建议使用const定义代替宏。

6、宏缺乏类型检查,尽量使用函数代替宏

七 质量保证

1、代码要具有正确性、简洁性、可维护、可测试、高性能、可移植性

2、操作符优先级不确定加括号

3、避免内存操作越界、内存泄露
注意数组分配内存、数组下标、指针加减操作、字符串操作等。
函数异常出口出要判断资源是否全部释放。
禁止使用已经被释放的内存。

4、考虑边界值的情况
考虑清楚使用 “>=、<=” 还是 “>、< ”。
对变量进行运算时,考虑有效范围。如:char型变量有效值范围-128到127。

5、使用if…else if结构时应由else子句结束;if语句也尽量加上else

6、使用switch结构时应有default分支

7、goto语句仅能用在函数异常退出前跳转去释放资源

八 程序效率

1、质量保证前提下优化代码,提高效率
优化数据结构与算法。

2、对于条件不变的重复运算要移出循环体外

3、避免来回跳跃访问多维数组成员

4、对于申请释放资源频繁的,创建资源库
比如线程池、内存池。

九 注释

1、注释要准确清晰,禁止代码与注释相矛盾
注释应放在代码上方或一行代码结束“;”后面。
除了常见缩写外,注释避免使用缩写。
禁止在一行代码内插入注释。

2、注释说明功能,不做名词解释
注释函数功能、传参要求、返回值。
全局变量要对其作用、含义、取值范围进行注释。

3、无用注释/注释代码要删除

4、文件顶部应对该文件内容相关信息进行注释
注释语言建议使用中文

5、项目组内应统一注释风格

十 排版与格式

1、代码缩进风格建议为4个空格

2、独立的代码块之间要换行隔开

3、一条语句过长但不能拆分的,需要换行编写

4、一行内只写一条语句

5、if、else if、else、for、do、while等语句独占一行
其随后的执行语句建议都增加{}。

6、双目运算符前后都加空格
逗号后加空格,单目运算符前后都不加空格。

7、注释符“//”、“/* */”与注释内容之间建议使用空格隔开

十一 表达式

1、复合表达式使用多种运算符,应使用括号明确运算次序
加括号还不能确定运算次序的,要拆分出多条语句。

2、赋值语句不能写在if条件判断表达式中,也不能当函数调用的参数
条件判断表达式需要赋值的,必须在if语句之前进行。
函数调用的参数不要是另一个函数调用。

十二 安全性

1、对用户的输入进行合法性检查

2、确保字符串都是以‘\0’为结束符
长度不明确的字符串不能放到固定长度的数组中。

3、对整数进行运算时,考虑有/无符号整数的有效范围,避免溢出
使用有/无符号整数,要避免符号错误。
避免较大整数转换为较小整数,导致高位数据丢失。

4、打印输出时确保格式化字符与参数匹配
格式化字符要由代码确定,用户输入只能作为参数。

5、读取文件数据的类型不确定时,不要使用依赖NULL结束符的函数
二进制数据的长度不能使用strlen()计算。

6、对IO操作要使用整型变量接收其返回值
IO函数返回值要进行错误提示检查,就不能将返回值类型转为char。

十三 可测性

1、模块划分清晰,接口明确,耦合性小,有明确输入与输出

2、集成测试与调试开关及其相应打印函数要统一,且有详细说明

3、调试打印的日志规定要统一
统一日志分类、级别。
日志内容与格式可以通过命令行、网管等方式配置和改变。
记录日志不建议在原子函数中,难以定位。

4、使用断言捕捉假设
断言只能用于逻辑条件判断,不能用于对输入数据的判断。

十四 可移植性

1、不能定义、重定义或取消定义标准库/平台中保留的标识符、宏和函数

2、不使用与硬件或操作系统关系很大的语句

3、避免使用嵌入式汇编

十五 单元测试

1、编写单元测试用例验证设计与编码

2、单元测试避免针对函数的测试

十六 代码编辑、编译

1、理解所有警告,修改代码消除所有警告
降低警告级别从而消除警告是不可取的。
要统一编译开关、静态检查选项和告警清除策略。

2、本地构建工具的配置与持续集成的一致
通过本地构建的代码要及时签入版本控制系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值