嵌入式软件编程规范.docx
《嵌入式软件编程规范.docx》由会员分享,可在线阅读,更多相关《嵌入式软件编程规范.docx(37页珍藏版)》请在冰豆网上搜索。
嵌入式软件编程规范
天津通卡嵌入式
C语言编码规范
V1.000
硬件开发中心
文档历史记录
版本号定义规则:
使用阿拉伯数字,并由小数点分割成两部分。
第一部分(1位有效数字):
整体修改时使用。
第二部分(3位有效数字):
部分调整时使用。
日期
姓名
版本更新记录
2016-03-10
李响
V0.001草稿。
参照北大青鸟、华为编程规范整理。
2016-03-24
李响
V1.000按部门讨论结果整理修改。
目录
1文件结构1
1.1版权和版本的声明1
1.2头文件的结构1
1.3定义文件的结构2
1.4头文件和定义文件使用3
2程序版式3
2.1空行3
2.2代码行4
2.3代码行内的空格5
2.4对齐5
2.5长行拆分6
2.6修饰符的位置7
2.7注释7
3标识符命名8
4常量9
4.1const与#define的比较9
4.2常量定义10
5变量10
6结构体11
7表达式和基本语句13
7.1运算符的优先级13
7.2复合表达式13
7.3if语句布尔表达式13
7.4循环语句15
7.5switch语句16
7.6goto语句16
8函数设计16
8.1注释规则16
8.2函数的使用16
8.3函数名16
8.4参数的规则16
8.5返回值的规则18
8.6函数内部实现的规则18
8.7其它建议19
9内存管理19
10可测性19
11程序效率19
12编译问题20
13兼容性问题20
14代码审查20
15代码测试、维护20
附录A:
通卡标准类型头文件及变量定义要求22
本规范适用于通卡公司硬件产品中自有嵌入式软件代码的编写。
对于第三方提供的代码(如:
驱动、系统文件、标准库等)可按其自有编码规范进行编写。
编程过程中尽量将第三方提供代码整理到单独的文件中,与自有代码进行区分。
1文件结构
C程序文件通常分为两类文件:
一类文件用于保存程序的声明(declaration),称为头文件。
头文件以“.h”为后缀。
另一类文件用于保存程序的实现(implementation),称为定义(definition)文件。
定义文件以“.c”为后缀。
对于简单的C语言程序,一般在把头文件和程序定义文件放在一起,只有一个.c定义文件即可。
而对于复杂的程序,则多采用头文件包含的形式并通过多个定义文件实现。
1.1版权和版本的声明
版权和版本的声明一般应该位于头文件和定义文件的开头(参见示例1-1),主要内容包括:
(1)版权信息;
(2)文件名称、文件标识、摘要;
(3)作者/修改者、修改日期、修改描述等;
/***********************************
*Copyright(c)2016,天津通卡
*Allrightsreserved.
*文件名称:
filename.h
*文件标识:
根据软件工程设置
*摘要:
简要描述本文件的作用和内容等
*************************************/
/************************************
*作者:
修改者名字,修改日期:
20XX年4月5日
*修改简要说明:
**************************************/
示例1-1版权和版本的声明
1.2头文件的结构
头文件由三部分内容组成:
(1)文件开头处的版权和版本声明(参见示例1-1);
(2)预处理块;
(3)声明函数原型和声明数据结构或变量等。
假设头文件名称为filename.h,头文件的结构参见示例1-2。
/*************************************
*Copyright(c)2016,天津通卡
*Allrightsreserved.
*
*文件名称:
filename.h
*文件标识:
根据软件工程设置
*摘要:
简要描述本文件的作用和内容等
****************************************/
#include
#include
#include//引用头文件
#ifndefFILENAME_H//防止filename.h被重复引用
#defineFILENAME_H
structstudentstruct
{
intno;
charname[20];
charsex;
floatscore;
};
voidGetValue();
voidSetValue(intno);
#endif
示例1-2C头文件结构
1.3定义文件的结构
定义文件有三部分内容:
(1)定义文件开头处的版权和版本声明(参见示例1-1);
(2)对一些头文件的引用;
(3)程序的实现体(包括数据和代码)。
假设定义文件的名称为filename.c,定义文件的结构参见示例1-3
/*版权和版本声明见示例1-1,此处省略。
*/
#inlcude“filename.h”
/*函数的实现体*/
voidGetValue()
{
…
}
/*函数的实现体*/
voidSetValue(intno)
{
…
}
voidmain()
{
…
}
示例1-3C定义文件的结构
1.4头文件和定义文件使用
【规则1-1-1】在复杂的工程文件中,为了防止头文件被重复引用,应使用ifndef/define/endif结构产生预处理块。
【规则1-1-2】用#include格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。
【规则1-1-3】用#include“filename.h”格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。
【规则1-1-4】不要在头文件中定义常量或变量,注意头文件只是用来声明。
【规则1-1-5】将非系统的函数库放在一个单独的目录下引用。
【规则1-1-6】头文件应按功能组织在一起,即对单独子系统的声明应放在单独的头文件中。
此外,当代码从一个平台移植到另一个平台时有可能发生更改的声明应位于单独的头文件中,并进行相应的注释。
【规则1-1-7】避免使用与函数库中专用头文件名相同的头文件名。
语句#include"math.h"如果在当前目录中找不到所期望文件的话,会包括标准库math头文件。
【规则1-1-8】包含头文件时一般不使用绝对路径名。
2程序版式
2.1空行
空行起着分隔程序段落的作用,空行得体将使程序的布局更加清晰。
空行不会浪费内存,所以不要舍不得用空行。
【规则2-1-1】在函数内部局部变量定义结束之后处理语句之前要加空行。
【规则2-1-2】在每个函数定义结束之后都要加空行。
参见示例2-1(a)。
【规则2-1-3】函数返回语句和其他语句之间使用空行分开。
【规则2-1-4】在一个函数体内,逻辑上密切相关的语句之间不加空行,其它地方应加空行分隔。
参见示例2-1(b)。
示例2-1(a)函数之间的空行示例2-1(b)函数内部的空行
2.2代码行
【规则2-2-1】一行代码只做一件事情,如只定义一个变量,或只写一条语句。
不允许把多个短语句写在一行中。
这样的代码容易阅读,并且方便写注释。
【规则2-2-2】if、for、while、do、case、switch、default等语句自占一行,执行语句不得紧跟其后。
不论执行语句有多少都要加{}表明是一个语句块。
【规则2-2-3】一对花括号要单独各占一行。
但是在do-while、struct和union及其后有‘;’的除外,要同在一行。
例如:
do
{
…
}while(i>0);
【规则2-2-4】switch语句中的每个case语句各占一行,当某个case语句不需要break语句最好加注释声明。
【规则2-2-5】尽可能在定义变量的同时初始化该变量(就近原则),如果变量的引用处和其定义处相隔较远,变量的初始化很容易被忘记。
如果引用了未被初始化的变量,可能会导致程序错误。
本建议可以减少隐患。
例如:
intwidth=20;/*定义并初绐化width*/
intheight=20;/*定义并初绐化height*/
intdepth=20;/*定义并初绐化depth*/
风格良好的代码行
风格不良的代码行
intwidth;/*宽度*/
intheight;/*高度*/
intdepth;/*深度*/
intwidth,height,depth;/*宽度高度深度*/
x=a+b;
y=c+d;
z=e+f;
x=a+b;y=c+d;z=e+f;
if(width{
dosomething();
}
if(widthfor(initialization;condition;update)
{
dosomething();
}
//空行
other();
for(initialization;condition;update)
dosomething();
other();
2.3代码行内的空格
【规则2-3-1】关键字之后要留空格。
象const、case等关键字之后至少要留一个空格,否则无法辨析关键字。
象if、for、while等关键字和紧跟的左括号‘(’之后应留一个空格,右括号前也对应要留一个空格,以突出关键字。
例如:
if(a==b)
【规则2-3-2】函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。
例如:
voidcalc(void);
【规则2-3-3】“,”之后要留空格,如Function(x,y,z)。
如果“;”不是一行的结束符号,其后要留空格,如for(initialization;condition;update)。
【规则2-3-4】不要在单目运算符(如“!
”、“~”、“++”、“--”、“&”)和其操作对象间加空格。
例如:
!
foo,++i,(long)getValue
【规则2-3-5】赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=”、“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格。
【规则2-3-6】象“[]”、“.”、“->”这类操作符前后不加空格。
例如:
big.bar,pFile->bar,big[bar]
【规则2-3-7】对于表达式较长的for语句和if语句,为了紧凑起见可以适当地去掉一些空格.
例如:
for(i=0;i<10;i++)和if((a<=b)&&(c<=d))
风格良好的空格
风格不良空格
voidFunc1(intx,inty,intz);
voidFunc1(intx,inty,intz);
if(year>=2000)
if((a>=b)&&(c<=d))
if(year>=2000)
if(a>=b&&c<=d)
for(i=0;i<10;i++)
for(i=0;i<10;i++)
for(i=0;i<10;i++)
int*x=&y;
int*x=&y;
array[5]=0;
a.Function();
b->Function();
array[5]=0;
1.Function();
b->Function();
2.4对齐
【规则2-4-1】程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。
在函数体的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。
【规则2-4-2】程序块要采用缩进风格编写,缩进的空格数为4个(定义一个tab键为四个空格)。
【规则2-4-3】同属于一个语句块的代码对齐。
【规则2-4-4】{}之内的代码块在‘{’右边一个tab键处左对齐。
【规则2-4-5】函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格,case语句下的情况处理语句也要遵从语句缩进要求。
风格良好的对齐
风格不良的对齐
voidFunction(intx)
{
programcode
}
voidFunction(intx){
programcode
}
if(condition)
{
programcode
}
else
{
programcode
}
if(condition){
programcode
}
else{
programcode
}
for(initialization;condition;update)
{
programcode
}
for(initialization;condition;update){
…programcode
}
while(condition)
{
programcode
}
while(condition){
…programcode
}
如果出现嵌套的{},则使用缩进对齐,如:
{
{
}
}
2.5长行拆分
【规则2-5-1】代码行最大长度宜控制在70至80个字符以内。
代码行不宜过长,否则不便于阅读,也不便于打印。
【规则2-5-2】长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。
拆分出的新行要进行适当的缩进,使排版整齐,语句可读。
【规则2-5-3】若函数或过程中的参数较长,则要进行适当的划分。
if((very_longer_variable1>=very_longer_variable12)
&&(very_longer_variable3<=very_longer_variable14)
&&(very_longer_variable5<=very_longer_variable16))
{
dosomething();
}
virtualCMatrixCMultiplyMatrix(CMatrixleftMatrix,
CMatrixrightMatrix);
for(very_long_initialization;
very_long_condition;
very_long_update)
{
dosomething();
}
示例2-5长行的拆分
2.6修饰符的位置
【规则2-6-1】将修饰符*和&紧靠变量名,以免引起误解。
例如:
char*name;
int*x;
2.7注释
C语言的注释符为“/*…*/”和“//”。
注释通常用于:
(1)版本、版权声明;
(2)函数接口说明,包括参数类型和意义、函数类型和意义等;
(3)重要的数据类型声明、变量、算法、处理、段落等提示。
“//”为行注释。
【规则2-7-1】注释是对代码作用的“提示”,而不是文档。
注释的频度要合适,一般要求占程序总行数的1/5~1/4。
【规则2-7-2】边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。
不再有用的注释要删除。
【规则2-7-3】注释应准确、易懂,防止注释有二义性。
错误的注释不但无益反而有害。
【规则2-7-4】尽量避免在注释中使用缩写,特别是不常用的缩写。
根据维护程序的对象确定使用中文还是使用英文。
【规则2-7-5】注释的位置应与被描述代码相邻,可以放在代码的上方或右方,一般不宜放在下方。
【规则2-7-6】对于所有有物理含义的变量、常量、数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,在声明时都必须加以注释。
示例:
/*activestatistictasknumber*/
#defineMAX_ACT_TASK_NUMBER1000
【规则2-7-7】全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明
【规则2-7-8】注释与所描述内容进行同样的缩排。
【规则2-7-9】将注释与其上面的代码用空行隔开。
【规则2-7-10】对变量的定义和分支语句(条件分支、循环语句等)必须编写注释。
【规则2-7-11】对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释。
说明:
这样比较清楚程序编写者的意图,有效防止无故遗漏break语句
【规则2-7-12】当代码段较长时,在程序块的结束行右方加注释标记,以表明某程序块的结束。
说明:
当代码段较长,特别是多重嵌套时,这样做可以使代码更清晰,更便于阅读。
示例:
参见如下例子。
if(...)
{
//programcode
while(index{
//programcode
}/*endofwhile(index}/*endofif(...)*///指明是哪条if语句结束
【规则2-7-13】当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。
【规则2-7-14】尽量不要在语句指令中添加注释。
【规则2-7-15】注释不具备约束使用者行为的能力。
【规则2-7-16】给一行代码添加注释最好使用“//”,比较清楚。
3标识符命名
共性规则是被大多数程序员采纳的,我们应当在遵循这些共性规则。
命名两个基本原则:
1.含义清晰,不易混淆;
2.不与其它模块、函数的命名空间相冲突。
【规则3-1-1】标识符要清楚、准确、简单而且尽量可发音的完整英文单词或大家基本可理解的缩写,避免使人产生误解。
如使用特殊约定或缩写,则要有注释说明。
例如:
intreturnStatus;
不要把currentValue写成nowValue。
【规则3-1-2】标识符的长度应当符合“min-length&&max-information”(最短并包含信息最多)原则。
单字符的名字也是有用的,常见的如i、j、k、m、n、x、y、z等,它们通常可用作函数内的局部循环变量。
【规则3-1-3】命名规则尽量与所采用的操作系统或开发工具的风格保持一致,并在同一项目中统一。
例如Windows应用程序的标识符通常采用“大小写”混排的方式,如printStudent;而Unix应用程序的标识符通常采用“小写加下划线”的方式,如print_student。
别把这两类风格混在一起用。
【规则3-1-4】尽量选择通用词汇并保持整个软件风格一致。
例如:
使用get、read、fetch、retrieve都能表达“取出”的意思,一旦软件采用哪一个则应贯穿始终。
【规则3-1-5】程序中不要出现仅靠大小写区分的相似的标识符。
例如:
intx,X;/*变量x与X容易混淆*/
voidfoo(inty);/*函数foo与FOO容易混淆*/
voidFOO(floaty);
【规则3-1-6】程序中不要出现标识符完全相同的局部变量和全局变量,尽管可能两者的作用域不同而不会发生语法错误,但会使人误解。
【规则3-1-7】变量的名字应当使用“名词”或者“形容词+名词”。
例如:
floatvalue;
floatnewValue;
【规则3-1-8】用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。
说明:
下面是一些在软件中常用的反义词组。
add/removebegin/endcreate/destroy
insert/deletefirst/lastget/release
increment/decrementput/get
add/deletelock/unlockopen/close
min/maxold/newstart/stop
next/previoussource/targetshow/hide
send/receivesource/destination
cut/pasteup/down
例如:
tk_uint16uiMinValue;
tk_uint16uiMaxValue;
tk_uint16MinValue(void);
tk_uint16MaxValue(void);
【规则3-1-9】局部变量和参数首字母或前两字母用于表明类型并小写,每个英文单词的第一个字母大写,其它小写,参见附录A《通卡标准类型头文件及变量定义要求》。
【规则3-1-10】常量前加前缀c_,下划线后命名规则同局部变量定义规则。
consttk_uint16c_uiMaxLength=100;
【规则3-1-11】宏定义全用大写字母,用下划线分割单词。
#defineMAX_LENGTH100;
【规则3-1-12】尽量减少使用宏函数。
宏函数定义采用F_+大写字母单词,用下划线分割单词。
#defineF_HEX2BCD(x)(((x)/10)<<4)+((x)%10)//转bcdx加括号
【规则3-1-13】静态变量加前缀s_(表示static)。
staticints_initValue;/*静态变量*/
【规则3-1-14】如果需要定义全局变量,则变量加前缀g_(表示global)。
例如:
intg_howStudent;/*全局变量*/
【规则3-1-15】函数名用大写字母开头的单词组合而成。
由多个单词组成的标识符每个单词首字母大写。
其它小写。
例如:
InputStudentInfo();//全局函数
【规则3-1-16】尽量避免名字中出现数字编号,如value1、value2等,除非逻辑上的确需要编号。
4常量
常量是一种标识符,它的值在运行期间恒定不变。
C语言用#define来定义常量。
除了#define之外还可以用const来