为了提高源程序的质量和可维护性,从而最终提高软件产品生产力,特编写此规范。本标准规定了程序设计人员进行程序设计时必须遵循的规范。本规范主要针对单片机编程语言和08编译器而言,包括排版、注释、命名、变量使用、代码可测性、程序效率、质量保证等内容。 ' J3 J1 h U( J F$ ~5 s4 a1 q
1.基本规则
+ ~8 L; F: z0 E; o. e1 v1 S格式清晰、注释简明扼要、命名规范易懂、函数模块化、程序易读易维护、功能准确实现、代码空间效率和时间效率高、适度的可扩展性、单片机编程规范-标识符命名
* d7 b. s# s5 y' |: m( c2.标识符命名 2.1 命名基本原则
1 t& w* R* _2 t8 [: ](1)命名清晰明了,有明确含义,使用完整单词或约定俗成的缩写。通常,较短的单词可通过去掉元音字母形成缩写;较长的单词可取单词的头几个字母形成缩写。即"见名知意"。(2)命名风格要自始至终保持一致。
- ~4 I) Q, T3 R6 r" m1 `1 d(3)命名中若使用特殊约定或缩写,要有注释说明。
# e r" w% w% a% b(4)同一软件产品内模块之间接口部分的标识符名称之前加上模块标识。; T% }2 H$ N. z* F) o
2.2 宏和常量命名
: t6 l2 o, n$ u& J& a" e6 J C宏和常量用全部大写字母来命名,词与词之间用下划线分隔。对程序中用到的数字均应用有意义的枚举或宏来代替。: O* P) j! l) u% w8 g
2.3 变量命名 s: C& ?$ Y5 b6 R- h6 O
变量名用小写字母命名,每个词的第一个字母大写。类型前缀(u8\s8 etc.)全局变量另加前缀g_。
. w% S- t& z' D$ q& a局部变量应简明扼要。局部循环体控制变量优先使用i、j、k等;局部长度变量优先使用len、num等;临时中间变量优先使用temp、tmp等。/ Q' {* x) X0 F4 e# c
2.4 函数命名
$ y, B3 P" a% p) E" n) w2 ~ v" Q函数名用小写字母命名,每个词的第一个字母大写,并将模块标识加在最前面。& V( c/ y4 E N' R+ M
2.5 文件命名 0 Z0 A0 ?) j4 H+ @& v% F# K
一个文件包含一类功能或一个模块的所有函数,文件名称应清楚表明其功能或性质。
8 {2 @5 S) A7 I4 }每个.c文件应该有一个同名的.h文件作为头文件。 - t' [9 T/ u7 R. O% j y7 _6 E
3.注释 3.1 注释基本原则
2 E* V, {/ S2 L0 G4 l5 T; i有助于对程序的阅读理解,说明程序在"做什么",解释代码的目的、功能和采用的方法。
" F( A( p; E+ H+ T4 d4 C一般情况源程序有效注释量在30%左右。
0 x W! w4 z6 [6 h( w注释语言必须准确、易懂、简洁。( V, B4 p- T, Z3 @
边写代码边注释,修改代码同时修改相应的注释,不再有用的注释要删除。
7 d8 z+ |# I" x" w汇编和C中都用"//",取消";" 不使用段注释" /* */ "(调试时可用) * h1 v- y1 y+ m% @- L$ l
3.2 文件注释
" v( E" u3 V+ ~* J- z! g文件注释必须说明文件名、函数功能、创建人、创建日期、版本信息等相关信息。$ Y/ c- U1 d# l4 ?
修改文件代码时,应在文件注释中记录修改日期、修改人员,并简要说明此次修改的目的。所有修改记录必须保持完整。
) o0 u4 S: B. R: K# U文件注释放在文件顶端,用"/*……*/"格式包含。
# N( g8 ^0 t: b) c7 G, Z7 ^ Y注释文本每行缩进4个空格;每个注释文本分项名称应对齐。; O& J% C% w8 |- G6 P' _
/***********************************************************
2 @. u) I% `. C# B文件名称:( c( |; f% G& j% ^* X8 [+ \' I
作 者:7 Q1 x# Q* A. X4 R4 w) K
版 本:
) w8 V( K6 Z- k! H. j' U0 j0 ?说 明:# Q* q& J9 }2 y* A$ c
修改记录:- P- l0 a$ V8 n% m( o' b( m) {
***********************************************************/
2 _; l$ ?' ^% n( j, W- H3.3 函数注释 ' @/ [+ b4 u' q/ N
3.3.1 函数头部注释9 |. \: O% N& v' U9 ^# F8 V
函数头部注释应包括函数名称、函数功能、入口参数、出口参数等内容。如有必要还可增加作者、创建日期、修改记录(备注)等相关项目。
- n$ @- c6 r" o3 O- A5 Y% {函数头部注释放在每个函数的顶端,用"/*……*/"的格式包含。其中函数名称应简写为Name(),不加入、出口参数等信息。( z7 t/ T% P" [1 ^2 ]) y# z9 _
/***********************************************************1 q4 m: R. Y2 W& U1 ?: b
函数名称:
0 B6 }' r3 g2 r- y/ z函数功能:+ Q) `. Q. ^/ |$ ^
入口参数:' }7 k; R3 H8 E; `- S" O& M- B
出口参数:
, n: i' Y, [ ~# |/ O; q备 注:5 F: r& U& l# \! }) U
***********************************************************/
2 w* x/ H/ j) s6 g( e" i+ M2 z+ @3.3.2 代码注释4 g, l5 e! v/ a& _, N
代码注释应与被注释的代码紧邻,放在其上方或右方,不可放在下面。如放于上方则需与其上面的代码用空行隔开。一般少量注释应该添加在被注释语句的行尾,一个函数内的多个注释左对齐;较多注释则应加在上方且注释行与被注释的语句左对齐信盈达嵌入式企鹅要妖气呜呜吧久零就要。
8 Q9 _$ K5 `7 k5 r( j函数代码注释用"//…//"的格式。
3 b8 c6 D* S* |+ G; j9 [通常,分支语句(条件分支、循环语句等)必须编写注释。其程序块结束行"}"的右方应加表明该程序块结束的标记"end of ……", 尤其在多重嵌套时。( d0 M& [- @+ q( [8 H$ N' N
3.4 变量、常量、宏的注释 3 v8 h$ l4 `- i: Q6 _
同一类型的标识符应集中定义,并在定义之前一行对其共性加以统一注释。对单个标识符的注释加在定义语句的行尾。
* t/ e! W" p3 p, @1 }) X/ m g全局变量一定要有详细的注释,包括其功能、取值范围、哪些函数或过程存取它以及存取时的注意事项等。
4 b- ]# N1 l/ A: _5 d o注释用"//…//"的格式。 + O c. k0 o1 n O4 g1 g" K
4.函数 4.1 函数设计原则
! _3 _8 U3 \/ o: `3 H) G, y0 o函数的基本要求:
1 G3 D7 C2 I* K3 \4 u5 u8 \" y' l1 O6 G1)封装性
* Q9 e/ f8 B( ]0 B3 p1) 正确性:程序要实现设计要求的功能。9 j4 k/ F9 B2 \2 u
2) 稳定性和安全性:程序运行稳定、可靠、安全。2 ?/ A# K: g* x* d, N% ?; e7 Q) r
3) 可测试性:程序便于测试和评价。* u; D+ [9 @0 ^0 h3 k1 V, h4 N
4) 规范/可读性:程序书写风格、命名规则等符合规范。
' z3 G4 I( M3 v* b t5) 扩展性:代码为下一次升级扩展留有空间和接口。
- d1 z0 s! L p5 |' m6) 全局效率:软件系统的整体效率高。& d6 o) \! x {4 S' H5 U
7) 局部效率:某个模块/子模块/函数的本身效率高。0 t' A. {3 K. `! g7 Z! ]. r
编制函数的基本原则:
8 i# N2 s+ A: ?1) 单个函数的规模尽量限制在200行以内(不包括注释和空行)。一个函数只完成一个功能。
! l! l+ ]; X6 t1 h; R! \; B2) 函数局部变量的数目一般不超过5~10个。9 p# y" q, _: [. U$ }0 P, \
3) 函数内部局部变量定义区和功能实现区(包含变量初始化)之间空一行。
9 j) `8 w/ Q- X) ~* z4) 函数名应准确描述函数的功能。通常使用动宾词组为执行某操作的函数命名。
\' J- _; L M; H, F4 g3 M6 G0 B5) 函数的返回值要清楚明了,尤其是出错返回值的意义要准确无误。& T! r9 t- s% g" F# z; x
6) 不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或强制的转换方式作为返回值返回。6 I6 `( I! E. c
7) 减少函数本身或函数间的递归调用。. t8 q8 Y1 J, m. }7 A% o
8) 尽量不要将函数的参数作为工作变量。
- _3 z- ]$ O# M: C4.2 函数定义
( F: x+ U& G' `- y1) 函数若没有入口参数或者出口参数,应用void明确申明。
+ J0 W1 J0 S' v& U c+ Y2) 函数名称与出口参数类型定义间应该空一格且只空一格。
9 H) B3 D5 J9 l& Q' P3) 函数名称与括号()之间无空格。
9 c- C/ n5 @0 Z4) 函数形参必须给出明确的类型定义。5 w9 a9 p" ]0 W; O) g( R# O: ^
5) 多个形参的函数,后一个形参与前一个形参的逗号分割符之间添加一个空格。3 P, B8 ]8 f( v1 A4 c7 K
6) 函数体的前后花括号"{}" 各独占一行。
/ m- F0 X) a; n$ k5 C# }4.3 局部变量定义 _1 h& u9 G* d/ x- k4 `9 C& P1 i
1) 同一行内不要定义过多变量。
+ b. D( }/ J8 d, C( h7 X* y" ?7 {3 ^2) 同一类的变量在同一行内定义,或者在相邻行定义。
/ S: z, A& p& j; g H0 g3) 先定义data型变量,再定义idtata型变量,再定义xdata型变量.(?): h9 V' m: ` X
4) 数组、指针等复杂类型的定义放在定义区的最后。
0 B2 t' k! }0 M$ t0 E5) 变量定义区不做较复杂的变量赋值。2 k: R) ~3 ~% v8 d |
4.4 功能实现区规范
+ m9 B2 X' `1 s# A, D1) 一行只写一条语句。/ z1 e( A( M0 [& {
2) 注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级信盈达嵌入式企鹅要妖气呜呜吧久零就要。
+ w4 A6 f1 \8 R9 }2 f( j5 h0 A3) 各程序段之间使用一个空行分隔,加以必要的注释。程序段指能完一个较具体的功能的一行或多行代码。程序段内的各行代码之间相互依赖性较强。(1、2、3方式)
% p, B& V( l# g4 T8 U \4) 不要使用难懂的技巧性很高的语句。
4 u Q' {: C4 S9 ^5) 源程序中关系较为紧密的代码应尽可能相邻。/ X& O5 n0 J. y) z1 Z2 e7 k
6) 完成简单功能、关系非常密切的一条或几条语句可编写为函数或定义为宏。 / p: A' S0 {* @% b+ K, d
5. 单片机编程规范-排版
! L' G* c9 }; V! j9 l6 s5.1 缩进
) f. U8 D+ ]1 w0 g G代码的每一级均往右缩进4个空格的位置。不使用Tab键
6 @7 n x% N1 d% \0 R% `) p5.2 分行 ' n( ~- L, {5 V1 [% e
每行语句(?????超过80个字符)要分成多行书写;长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进适当的缩进,使排版整齐,语句可读。避免把注释插入分行中。
3 W( L$ ^" B! ^! G" p+ {/ k5.3 空行
T4 ~. s, l! H( X1) 文件注释区、头文件引用区、函数间应该有且只有一行空行。
) k& j+ P7 k Q; ?4 R! t) j2) 相邻函数之间应该有且只有一行空行。; x+ Y, @8 P6 K
3) 函数体内相对独立的程序块之间可以用一行空行或注释来分隔。. T% y* \( L2 j4 [
4) 函数注释和对应的函数体之间不应该有空行。( `- G/ E+ q& |! W3 q
5) 文件末尾有且只有一行空行。4 k* ]" N. t, I; ~/ O( y4 V0 N
5.4 空格 1 Y( J$ d+ j* E9 M! O% h
1) 函数语句尾部或者注释之后不能有空格。, o* j/ E' \$ I5 V3 f" w1 ]9 ~: r
2) 括号内侧(即左括号后面和右括号前面)不加空格,多重括号间不加空格。
1 ?/ Y1 M- t7 p! x! e3) 函数形参之间应该有且只有一个空格(形参逗号后面加空格)。
5 b: x m* b/ }4) 同一行中定义的多个变量间应该有且只有一个空格(变量逗号后面加空格)。' Q% V2 h8 Y P3 W9 U5 j
5) 表达式中,若有多个操作符连写的情况,应使用空格对它们分隔:' N7 E! T1 t9 J" u) H
6) 在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符前后均加一个空格;在两个以上的关键字、变量、常量进行非对等操作时,其前后均不应加空格;
* _, d; F- ]$ b0 P7) 逗号只在后面加空格;) j( Y. D8 d0 b) H4 B
8) 双目操作符,如比较操作符, 赋值操作符"="、"+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位操作符"<<"、"^"等,前后均加一个空格;
" ]. `! p3 N0 o9) 单目操作符,如"!"、"~"、"++"、"-"、"&"(地址运算符)等,前后不加空格;
8 }8 ~8 A! E3 C' W1 ~2 g10) "->"、"."前后不加空格;
' p" H% Y6 w: Z, M4 Q8 w$ U+ y8 t11) if、for、while、switch等关键字与后面的括号间加一个空格;! C p, | b% B
5.5 花括号
# O( x6 ^$ n& v1) if、else if、else、for、while语句无论其执行体是一条语句还是多条语句都必须加花括号,且左右花括号各独占一行。
n( V7 I$ v6 I2 u5 U& {( {( y/ j2) do{}while()结构中,"do"和"{"均各占一行,"}"和"while();"共同占用一行。
* L7 _6 y8 G) ~* p8 eif ( ) do
: h' l' v5 y+ ~1 }* n- a m{ {# X5 a. Q7 ?: D4 M
} }while( );3 O4 ^) j8 a/ _) g1 ~4 [
else# E0 e! q2 I9 H' [4 d0 F, J
{' ^' z! a, [' ~! [( B0 h* R: i9 Y
}
4 U' t& V% K& r$ A9 a嵌套越少越好,{}不准超过3层
) ^& U# n8 o I3 m7 J5.6 switch语句 9 [9 n5 W6 m; e4 z8 g5 r# h
1) 每个case和其判据条件独占一行。2 H; J4 a/ v( G1 i' y9 G
2) 每个case程序块需用break结束。特殊情况下需要从一个case块顺序执行到下一个case块的时候除外,但需要花括号在交界处明确注释如此操作的原因,以防止出错。
! g5 A" X* d" ~5 f% K0 `3) case程序块之间空一行,且只空一行。( y" J$ n5 Z5 y! _- }3 x6 W
4) 每个case程序块的执行语句保持4个空格的缩进。) w8 v: U4 ]) W: [8 Y$ O1 f
5) 一般情况下都应该包含default分支。
' k S# G9 ]2 l8 h) k1 ]% pSwitch ( )
( v7 |; b) }: N+ j) |2 O/ n1 Y{
8 o3 Q2 }5 ]# d8 bcase x:
/ P: R) @' V2 `) n, [3 Z Ybreak;
' v) {1 ^* ?& c/ b( s3 A- K/ ucase x:
, r2 T) C1 v V- ebreak;0 W; S6 G7 U# q; i8 c% D' K+ p# ?2 q# i
default:, K( G4 C- B4 z% N/ h( t, w* L
break;5 S4 a) X# A. v5 }8 V/ V
}
1 P( r$ |( W- m& u/ j6.程序结构 6.1 基本要求 9 T+ y- x3 U* l1 J
1) 有main()函数的.c文件应将main()放在最前面,并明确用void声明参数和返回值。
9 F' g* |. B6 P6 c2) 对由多个.c文件组成的模块程序或完整监控程序,建立公共引用头文件,将需要引用的库头文件、标准寄存器定义头文件、自定义的头文件、全局变量等均包含在内,供每个文件引用。通常,标准函数库头文件采用尖角号< >标志文件名,自定义头文件采用双撇号″″标志文件名。- A% T$ Y8 H. p$ [
3) 每个.c文件有一个对应的.h文件,.c文件的注释之后首先定义一个唯一的文件标志宏,并在对应的.h文件中解析该标志。
; ?6 [( W6 I) O+ c5 q在.c文件中:0 n2 y4 E/ c( ?. R: K
#define FILE_FLAG
% i; Z! |& n4 w! x* w在.h文件中:&
7 a8 G" ~# e5 s4 {1 Y6.程序结构 6.1 基本要求
" l+ F4 x( F! b; ^. B: M* K1) 有main()函数的.c文件应将main()放在最前面,并明确用void声明参数和返回值。' z0 H- V/ H* {% }4 t* k
2) 对由多个.c文件组成的模块程序或完整监控程序,建立公共引用头文件,将需要引用的库头文件、标准寄存器定义头文件、自定义的头文件、全局变量等均包含在内,供每个文件引用。通常,标准函数库头文件采用尖角号< >标志文件名,自定义头文件采用双撇号″″标志文件名。
* t4 X' J: N, f* D" i5 a3) 每个.c文件有一个对应的.h文件,.c文件的注释之后首先定义一个唯一的文件标志宏,并在对应的.h文件中解析该标志。' O" ]7 p& X( f8 y3 M. p
在.c文件中:
. I0 N" q |) U#define FILE_FLAG3 g/ _$ G8 n/ X0 i0 D" O" s5 X
在.h文件中:
9 _9 ]& \. H6 s* i, i4 r( k% V#ifdef FILE_FLAG
6 M6 `5 ~ Y9 Y# z8 C8 n#define XXX
% {. J, F* T8 g2 U x' B#else
% Z$ n: j& R% O* C$ u, l#define XXX extern
4 [* W c( l. Z. V. e3 t#endif$ m# }& D$ e; p% o) d9 p
4) 对于确定只被某个.c文件调用的定义可以单独列在一个头文件中、单独调用。
2 [" H! D2 y6 M) h. ^* z/ t 9 q. u8 ~" V# E7 a' x: z2 S1 r# ?
|