keil编译规范
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
keil编译规范
1 前⾔
为了提⾼源程序的质量和可维护性,从⽽最终提⾼软件产品⽣产⼒,特编写此规范。
2 范围
本标准规定了程序设计⼈员进⾏程序设计时必须遵循的规范。
本规范主要针对C51编程语⾔和keil编译器⽽⾔,包括排版、注释、命名、变量使⽤、代码可测性、程序效率、质量保证等内容。
3 总则
l 格式清晰
l 注释简明扼要
l 命名规范易懂
l 函数模块化
l 程序易读易维护
l 功能准确实现
l 代码空间效率和时间效率⾼
l 适度的可扩展性
4 数据类型定义
编程时统⼀采⽤下述新类型名的⽅式定义数据类型。
建⽴⼀个datatype.h⽂件,在该⽂件中进⾏如下定义:
typedef bit BOOL; // 位变量//
typedef unsigned char INT8U; // ⽆符号8位整型变量// typedef signed char INT8S; // 有符号8位整型变量// typedef unsigned int INT16U; // ⽆符号16位整型变量// typedef signed int INT16S; // 有符号16位整型变量// typedef unsigned long INT32U; // ⽆符号32位整型变量// typedef signed long INT32S; // 有符号32位整型变量// typedef float FP32; // 单精度浮点数(32位长度) // typedef double FP64; // 双精度浮点数(64位长度) //
5 标识符命名
5.1 命名基本原则
l 命名要清晰明了,有明确含义,使⽤完整单词或约定俗成的缩写。
通常,较短的单词可通过去掉元⾳字母形成缩写;较长的单词可取单词的头⼏个字母形成缩写。
即"见名知意"。
l 命名风格要⾃始⾄终保持⼀致。
l 命名中若使⽤特殊约定或缩写,要有注释说明。
l 除了编译开关/头⽂件等特殊应⽤,应避免使⽤以下划线开始和/或结尾的定义。
l 同⼀软件产品内模块之间接⼝部分的标识符名称之前加上模块标识。
5.2 宏和常量命名
宏和常量⽤全部⼤写字母来命名,词与词之间⽤下划线分隔。
对程序中⽤到的数字均应⽤有意义的枚举或宏来代替。
5.3 变量命名
变量名⽤⼩写字母命名,每个词的第⼀个字母⼤写。
类型前缀(u8\s8 etc.)全局变量另加前缀g_。
局部变量应简明扼要。
局部循环体控制变量优先使⽤i、j、k等;局部长度变量优先使⽤len、num等;临时中间变量优先使⽤temp、tmp 等。
函数名⽤⼩写字母命名,每个词的第⼀个字母⼤写,并将模块标识加在最前⾯。
5.5 ⽂件命名
⼀个⽂件包含⼀类功能或⼀个模块的所有函数,⽂件名称应清楚表明其功能或性质。
每个.c⽂件应该有⼀个同名的.h⽂件作为头⽂件。
6 注释
6.1 注释基本原则
l 有助于对程序的阅读理解,说明程序在"做什么",解释代码的⽬的、功能和采⽤的⽅法。
l ⼀般情况源程序有效注释量在30%左右。
l 注释语⾔必须准确、易懂、简洁。
l 边写代码边注释,修改代码同时修改相应的注释,不再有⽤的注释要删除。
6.2 ⽂件注释
⽂件注释必须说明⽂件名、函数功能、创建⼈、创建⽇期、版本信息等相关信息。
修改⽂件代码时,应在⽂件注释中记录修改⽇期、修改⼈员,并简要说明此次修改的⽬的。
所有修改记录必须保持完整。
⽂件注释放在⽂件顶端,⽤"/*……*/"格式包含。
注释⽂本每⾏缩进4个空格;每个注释⽂本分项名称应对齐。
/*********************************************** ************
⽂件名称:
作者:
版本:
说明:
修改记录:
*********************************************** ************/
6.3 函数注释
6.3.1 函数头部注释
函数头部注释应包括函数名称、函数功能、⼊⼝参数、出⼝参数等内容。
如有必要还可增加作者、创建⽇期、修改记录(备注)等相关项⽬。
函数头部注释放在每个函数的顶端,⽤"/*……*/"的格式包含。
其中函数名称应简写为FunctionName(),不加⼊、出⼝参数等信息。
/*********************************************** ************
函数名称:
函数功能:
⼊⼝参数:
出⼝参数:
备注:
*********************************************** ************/
代码注释应与被注释的代码紧邻,放在其上⽅或右⽅,不可放在下⾯。
如放于上⽅则需与其上⾯的代码⽤空⾏隔开。
⼀般少量注释应该添加在被注释语句的⾏尾,⼀个函数内的多个注释左对齐;较多注释则应加在上⽅且注释⾏与被注释的语句左对齐。
函数代码注释⽤"//…//"的格式。
通常,分⽀语句(条件分⽀、循环语句等)必须编写注释。
其程序块结束⾏"}"的右⽅应加表明该程序块结束的标记"end of ……", 尤其在多重嵌套时。
6.4 变量、常量、宏的注释
同⼀类型的标识符应集中定义,并在定义之前⼀⾏对其共性加以统⼀注释。
对单个标识符的注释加在定义语句的⾏尾。
全局变量⼀定要有详细的注释,包括其功能、取值范围、哪些函数或
过程存取它以及存取时的注意事项等。
注释⽤"//…//"的格式。
7 函数
7.1 设计原则
函数的基本要求:
l 正确性:程序要实现设计要求的功能。
l 稳定性和安全性:程序运⾏稳定、可靠、安全。
l 可测试性:程序便于测试和评价。
l 规范/可读性:程序书写风格、命名规则等符合规范。
l 扩展性:代码为下⼀次升级扩展留有空间和接⼝。
l 全局效率:软件系统的整体效率⾼。
l 局部效率:某个模块/⼦模块/函数的本⾝效率⾼。
编制函数的基本原则:
l 单个函数的规模尽量限制在200⾏以内(不包括注释和空⾏)。
⼀个函数只完成⼀个功能。
l 函数局部变量的数⽬⼀般不超过5~10个。
l 函数内部局部变量定义区和功能实现区(包含变量初始化)之间空⼀⾏。
l 函数名应准确描述函数的功能。
通常使⽤动宾词组为执⾏某操作的函
数命名。
l 函数的返回值要清楚明了,尤其是出错返回值的意义要准确⽆误。
l 不要把与函数返回值类型不同的变量,以编译系统默认的转换⽅式或强制的转换⽅式作为返回值返回。
l 减少函数本⾝或函数间的递归调⽤。
l 尽量不要将函数的参数作为⼯作变量。
7.2 函数定义
l 函数若没有⼊⼝参数或者出⼝参数,应⽤void明确申明。
l 函数名称与出⼝参数类型定义间应该空⼀格且只空⼀格。
l 函数名称与括号()之间⽆空格。
l 函数形参必须给出明确的类型定义。
l 多个形参的函数,后⼀个形参与前⼀个形参的逗号分割符之间添加⼀个空格。
l 函数体的前后花括号"{}" 各独占⼀⾏。
7.3 局部变量定义
l 同⼀⾏内不要定义过多变量。
l 同⼀类的变量在同⼀⾏内定义,或者在相邻⾏定义。
l 先定义data型变量,再定义idtata型变量,再定义xdata型变量.
l 数组、指针等复杂类型的定义放在定义区的最后。
l 变量定义区不做较复杂的变量赋值。
7.4 功能实现区规范
l ⼀⾏只写⼀条语句。
l 注意运算符的优先级,并⽤括号明确表达式的操作顺序,避免使⽤默认优先级。
l 各程序段之间使⽤⼀个空⾏分隔,加以必要的注释。
程序段指能完⼀个较具体的功能的⼀⾏或多⾏代码。
程序段内的各⾏代码之间相互依赖性较强。
l 不要使⽤难懂的技巧性很⾼的语句。
l 源程序中关系较为紧密的代码应尽可能相邻。
l 完成简单功能、关系⾮常密切的⼀条或⼏条语句可编写为函数或定义为宏。
8 排版
8.1 缩进
代码的每⼀级均往右缩进4个空格的位置。
8.2 分⾏
过长的语句(超过80个字符)要分成多⾏书写;长表达式要在低优先级操作符处划分新⾏,操作符放在新⾏之⾸,划分出的新⾏要进适当的缩进,使排版整齐,语句可读。
避免把注释插⼊分⾏中。
8.3 空⾏
l ⽂件注释区、头⽂件引⽤区、函数间应该有且只有⼀⾏空⾏。
l 相邻函数之间应该有且只有⼀⾏空⾏。
l 函数体内相对独⽴的程序块之间可以⽤⼀⾏空⾏或注释来分隔。
l 函数注释和对应的函数体之间不应该有空⾏。
l ⽂件末尾有且只有⼀⾏空⾏。
8.4 空格
l 函数语句尾部或者注释之后不能有空格。
l 括号内侧(即左括号后⾯和右括号前⾯)不加空格,多重括号间不加空格。
l 函数形参之间应该有且只有⼀个空格(形参逗号后⾯加空格)。
l 同⼀⾏中定义的多个变量间应该有且只有⼀个空格(变量逗号后⾯加空格)。
l 表达式中,若有多个操作符连写的情况,应使⽤空格对它们分隔:
在两个以上的关键字、变量、常量进⾏对等操作时,它们之间的操作符前后均加⼀个空格;在两个以上的关键字、变量、常量进⾏⾮对等操作时,其前后均不应加空格;
逗号只在后⾯加空格;
双⽬操作符,如⽐较操作符, 赋值操作符"="、"+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位操作符"<<"、"^"等,前后均加⼀个空格;
单⽬操作符,如"!"、"~"、"++"、"-"、"&"(地址运算符)等,前后不加空格;
"->"、"."前后不加空格;
if、for、while、switch等关键字与后⾯的括号间加⼀个空格;
8.5 花括号
l if、else if、else、for、while语句⽆论其执⾏体是⼀条语句还是多条语句都必须加花括号,且左右花括号各独占⼀⾏。
l do{}while()结构中,"do"和"{"均各占⼀⾏,"}"和"while();"共同占⽤⼀⾏。
if ( ) do
{ {
} }while( );
else
{
}
8.6 switch语句
l 每个case和其判据条件独占⼀⾏。
l 每个case程序块需⽤break结束。
特殊情况下需要从⼀个case块顺序执⾏到下⼀个case块的时候除外,但需要在交界处明确注释如此操作的原因,以防⽌出错。
l case程序块之间空⼀⾏,且只空⼀⾏。
l 每个case程序块的执⾏语句保持4个空格的缩进。
l ⼀般情况下都应该包含default分⽀。
Switch ( )
{
case x:
break;
case x:
break;
default:
break;
}
9 程序结构
9.1 基本要求
l 有main()函数的.c⽂件应将main()放在最前⾯,并明确⽤void声明参数和返回值。
l 对由多个.c⽂件组成的模块程序或完整监控程序,建⽴公共引⽤头⽂件,将需要引⽤的库头⽂件、标准寄存器定义头⽂件、⾃定义的头⽂件、全局变量等均包含在内,供每个⽂件引⽤。
通常,标准函数库头⽂件采⽤尖⾓号< >标志⽂件名,⾃定义头⽂件采⽤双撇号″″标志⽂件名。
l 每个.c⽂件有⼀个对应的.h⽂件,.c⽂件的注释之后⾸先定义⼀个唯⼀的⽂件标志宏,并在对应的.h⽂件中解析该标志。
在.c⽂件中:
#define FILE_FLAG
在.h⽂件中:
#ifdef FILE_FLAG
#define XXX
#else
#define XXX extern
#endif
l 对于确定只被某个.c⽂件调⽤的定义可以单独列在⼀个头⽂件中、单独调⽤。
9.2 可重⼊函数
可重⼊函数中若使⽤了全局变量,应通过关中断、信号量等操作⼿段对其加以保护。
9.3 函数的形参
l 由函数调⽤者负责检查形参的合法性。
l 尽量避免将形参作为⼯作变量使⽤。
9.4 循环
l 尽量减少循环嵌套层数
l 在多重循环中,应将最忙的循环放在最内层
aijun98012006-08-19 13:53 第⼀章:缩进格式
Tab是8个字符,于是缩进也是8个字符.有很多怪异的风格,他们将缩进格式定义为4个字符(设置为2个字符!)的深度,这就象试图将PI定义为3⼀样让⼈难以接受.
理由是:缩进的⼤⼩是为了清楚的定义⼀个块的开始和结束.特别是当你已经在计算机前⾯呆了20多个⼩时了以后,你会发现⼀个⼤的缩进格式使得你对程序的理解更容易.
现在,有⼀些⼈说,使⽤8个字符的缩进使得代码离右边很近,在80个字符宽度的终端屏幕上看程序很难受.回答是,但你的程序有3个以上的缩进的时候,你就应该修改你的程序.
总之,8个字符的缩进使得程序易读,还有⼀个附加的好处,就是它能在你将程序变得嵌套层数太多的时候给你警告.这个时候,你应该修改你的程序.
第⼆章:⼤符号的位置
另外⼀个C程序编程风格的问题是对⼤括号的处理.同缩进⼤⼩不同,⼏乎没有什么理由去选择⼀种⽽不选择另外⼀种风格,但有⼀种推荐的风格,它是Kernighan和Ritchie的经典的那本书带来的,它将开始
的⼤括号放在⼀⾏的最后,⽽将结束⼤括号放在⼀⾏的第⼀位,如下所⽰:
if (x is true) { we do y }
然⽽,还有⼀种特殊的情况:命名函数:开始的括号是放在下⼀⾏的第⼀位,如下:
int function(int x) { body of function }
所有⾮正统的⼈会⾮难这种不⼀致性,但是,所有思维正常的⼈明⽩: (第⼀) K&R是___对___的,(第⼆)如果K&R不对,请参见第⼀
条. (:-))......另外,函数也是特殊的,不⼀定⾮得⼀致.
需要注意的是结束的括号在它所占的那⼀⾏是空的,__除了__它跟随着同⼀条语句的继续符号.如"while"在do-while循环中,或者"else"在if语句中.如下:
do { body of do-loop } while (condition);
以及
if (x == y) { .. } else if (x > y) { ... } else { .... }
理由: K&R.
另外,注意到这种⼤括号的放置⽅法减⼩了空⾏的数量,但却没有减少可读性.于是,在屏幕⼤⼩受到限制的时候,你就可以有更多的空⾏来写些注释了.
第三章:命名系统
C是⼀种简洁的语⾔,那么,命名也应该是简洁的.同MODULE-2以及ASCAL语⾔不同的是,C程序员不使⽤诸如ThisVariableIsATemporaryCounter之类的命名⽅式.⼀个C语⾔的程序员会将之命名为"tmp",这很容易书写,且并不是那么难以去理解.
然⽽,当混合类型的名字不得不出现的时候,描述性名字对全局变量来说是必要的了.调⽤⼀个名为"foo"全局的函数是很让⼈恼⽕的.全局变量(只有你必须使⽤的时候才使⽤它) ,就象全局函数⼀样,需
要描述性的命名⽅式.假如你有⼀个函数⽤来计算活动⽤户的数量,你应该这样命名--"count_active_users()"--或另外的相近的形式,你不应命名为"cntusr()".
有⼀种称为Hungarian命名⽅式,它将函数的类型编码写⼊变量名中,这种⽅式是脑⼦有⽑病的⼀种表现---编译器知道这个类型⽽且会去检查它,⽽这样只会迷惑程序员. --知道为什么Micro$oft为什么会⽣产这么多"臭⾍"程序了把!!.
局部变量的命名应该短⼩精悍.假如你有⼀个随机的整数循环计数器,它有可能有"i",如果没有任何可能使得它能被误解的话,将其写作"loop_counter"是效率低下的.同样的,""tmp"可以是任何临时数值的函数变量.
如果你害怕混淆你的局部变量的名字,还有另外⼀个问题,就是称function-growth-hormone-imbalancesyndrome.
第四章:函数
函数应该短⼩⽽迷⼈,⽽且它只作⼀件事情.它应只覆盖⼀到两个屏幕(80*24⼀屏),并且只作⼀件事情,⽽且将它做好.(这不就是UNIX的风格吗,译者注).
⼀个函数的最⼤长度和函数的复杂程度以及缩进⼤⼩成反⽐.于是,如果你已经写了简单但长度较长的的函数,⽽且你已经对不同的情况做了很多很⼩的事情,写⼀个更长⼀点的函数也是⽆所谓的.
然⽽,假如你要写⼀个很复杂的函数,⽽且你已经估计到假如⼀般⼈读这个函数,他可能都不知道这个函数在说些什么,这个时候,使⽤具有描述性名字的有帮助的函数.
另外⼀个需要考虑的是局部变量的数量.他们不应该超过5-10个,否则你有可能会出错.重新考虑这个函数,将他们分割成更⼩的函数.⼈的⼤脑通常可以很容易的记住7件不同的事情,超过这个数量会引起混乱.你知道你很聪明,但是你可能仍想去明⽩2周以前的做的事情.
第5章:注释
注释是⼀件很好的事情,但是过多的注释也是危险的,不要试图区解释你的代码是注释如何如何的好:你应该将代码写得更好,⽽不是花费⼤量的时间去解释那些糟糕的代码.
通常情况下,你的注释是说明你的代码做些什么,⽽不是怎么做。