编程规范.docx

上传人:b****6 文档编号:5761648 上传时间:2023-01-01 格式:DOCX 页数:16 大小:26.67KB
下载 相关 举报
编程规范.docx_第1页
第1页 / 共16页
编程规范.docx_第2页
第2页 / 共16页
编程规范.docx_第3页
第3页 / 共16页
编程规范.docx_第4页
第4页 / 共16页
编程规范.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

编程规范.docx

《编程规范.docx》由会员分享,可在线阅读,更多相关《编程规范.docx(16页珍藏版)》请在冰豆网上搜索。

编程规范.docx

编程规范

编程规范与原则

湘潭大学信息工程学院

作者:

刘新

Email:

liuxin_new@

版本号:

1.0

1.导言

1.1为何需要编程规范

编程规范与惯例对于程序员来说非常重要,有以下几点原因:

●编码是程序员的职责,一个好的信息技术产品必然有高质量的代码,高质量的代码首先一点它必须遵守某种编程规范。

●一个软件整个生命周期内成本的80%用于维护。

●几乎没有一个软件在整个生命周期内全部由它的原始作者来维护。

●编程规范改善了软件的可读性,使工程师更加快速、彻底的理解新代码。

●如果你的源代码被作为产品发布,那么你必须保证它和其它产品一样很好的包装并保持整洁。

●大量数据表明,软件存在问题或者隐患,很大一部分是由于未遵守基本准则所致,如果能在

●项目早期明确规则,则会避免许多麻烦。

●为了简化工作,每一个编写软件的人都必须遵守编程规范。

每个人!

1.2适用范围

本文阐述的编码规范主要使用在具备下面特性的软件:

●以C/C++为编程语言。

●资源受限的系统,对性能有较严格要求的的系统。

本规范中每一条款都有一个执行等级,分为:

●必须——代码无条件的满足必须等级的条款,不满足的代码必须得到修改,以满足相关的条款。

●推荐——条款非强制执行的,一般情况下遵照条款有助于改善代码的质量。

若不特别指出,所有条款执行”必须”等级。

2.基本原则

本规范的基本目的是提高代码的可维护性。

也就是说,代码必须是可读的、易于理解的、可测试的和可移植的。

2.1所有的代码必须符合业界标准

1、尽可能使用标准函数库,如ANSIC和STL。

2、所有的函数原型必须符合ANSI标准,单独在头文件中声明或者在源文件的预处理语句后声明,不要声明在函数内部;

3、原型声明中的形参要有类型和名称;

4、所有的参数定义必须写在圆括号中;

5、函数有返回值,一定要写返回值类型,没有返回值,一定要写void;

6、如果源程序中有main()函数,它必须是源程序中定义的第一个函数,返回值类型是int,要用return语句返回执行情况。

2.2保持代码简单直观

1、避免使用深度超过3层以上的嵌套语句(如3重以上循环和3重以上的分支结构)。

如碰上这种情况,请将内层语句写成函数形式。

2、避免编程语言中隐含或者晦涩的特性。

直接表达你的意图。

3、在一个表达式中,如果某变量使用了自加或自减运算符,该变量只允许出现一次。

如下表达式绝不允许出现:

k=i+i++;

4、规则3同样适用于函数调用时的参数传递,这样的调用不允许出现:

callFun(i,i++);

5、一条语句只做一件事情,不要用逗号表达式来代替多条语句。

6、循环要完成的工作,写在循环体中,循环控制部分尽量简单。

下面这种代码不允许出现:

for(cx=x,cy=y;r=cx%cy;cx=cy,cy=r);

while(scanf("%d",&n),n);

7、尽量不要使用goto语句。

goto语句只能在多重循环嵌套的最内层向最外层跳出时使用,且循环次数非常多(百万次级数以上)。

2.3请及时更新旧代码

受产品的资金、时间、范围的约束,你可能写出能工作但结构不优美、执行效率不高的代码,这情有可原,但不要对这种代码置之不管。

2.4保持良好的软件结构

一般情况下,好的软件结构具备如下特征:

●顶层函数的扇出较高

●中层函数的扇出较少

●底层函数则归入到公共模块中

2.5预留调试接口,对可能存在的错误作出预防

3.文件命名与组织

3.1扩展名

表1常用文件扩展名

文件类型

扩展名

备注

C源文件

.c

小写

C++源文件

.cpp

小写

C/C++头文件

.h

小写

3.2.常用文件名

表2常用文件名

文件名称

用途

Makefile

Makefile的首选名称。

RELEASE

程序发行说明,描述各个版本的主要更改、问题解决状况、尚未解决的问

题等等

README

总结项目目录的内容

ChangeLog

代码修改记录,详细描述对每个源文件所做的修改,最好精确到函数级别

4.代码结构

4.1文件头

文件头是嵌入在C/C++头文件或源文件中,在文件首部的注释块,一般包含如下信息:

●公司或组织的名称

●地址

●版权说明

●开发人员

●模块目的/功能

●文件版本

●修改日志

4.2C/C++头文件

头文件的布局如下:

文件头

版本历史

常量定义

全局宏定义

是否在头文件包含文件头,这有些争议,有些头文件较简单,可不必包含文件头。

但一般说来,公共头文件(接口/原型)需要带有文件头。

4.3C/C++源文件

源文件也即实现文件,其布局:

文件头

版本历史

#include区

#define区

宏定义区(Macros)

本地数据类型定义区(Localdatatypes)

本地变量区(Localvariables)

本地表(Localtables)

本地函数原型(Localfunctionprototypes)

全局函数(Globalfunctions)

局部函数(Localfunctions)

5.排版

5.1代码行宽度

推荐每行的代码宽度限制在80个字符内。

80个字符限制是由于旧显示器的约束,可视范围只有80个字符。

较长的语句(>80字符),要分成多行书写,,表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。

推荐:

太长的表达式可以分成多个较短的表达式来书写。

5.2TAB字符的使用

请将编辑器的TAB字符占位设置为4个空格。

5.3缩进

函数、结构、循环、判断等语句都需要采用缩进,缩进请使用一个TAB(4个空格)。

5.4空行

相对独立的程序块之间、变量说明之后必须加一个空行。

但不要随意添加无谓的空行。

例如,下面的写法不正确:

voidfunction1()

{

intvar1,var2;

var1=1;

var2=2;

}

正确的书写方法是:

voidfunction1()

{

intvar1,var2;

var1=1;

var2=2;

}

5.5不允许把多个短语句写在一行中

示例:

如下例子不符合规范

rect.length=0;rect.width=0;

应如下书写

rect.length=0;

rect.width=0;

5.6添加空格

在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如->),后不应加空格。

示例如下:

1、逗号、分号只在后面加空格

inta,b,c;

2、比较操作符,赋值操作符"="、"+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",

位域操作符"<<"、"^"等双目操作符的前后加空格。

if(current_time>=MAX_TIME_VALUE)

a=b+c;

a*=2;

a=b^2;

3、"!

"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。

*p='a';//内容操作"*"与内容之间

flag=!

isEmpty;//非操作"!

"与内容之间

p=&mem;//地址操作"&"与内容之间

i++;//"++","--"与内容之间

4、"->"、"."前后不加空格。

p->id=pid;//"->"指针前后不加空格

5、if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。

if(a>=b&&c>d)

5.7对于赋值语句,等号和数值保持垂直对齐。

(推荐)

示例:

DispSegTblIx=0;

DispDigMsk=0x80;

DispScale=1.25;

6.注释

6.1每一个注释都必须有用.

6.2对于函数要给出必要的注释

必须注释出:

:

函数的名称、功能、入口参数、出口参数、返回值、调用说明。

除非有把握使用英语明确表达你的用意。

一般情况下使用中文。

/**

*sample_func–summarythisfunction

*@param1:

descriptionofparam1

*@param2:

descriptionofparam2

*Detaildescripttheusuageofsample_func.

**/

intsample_func(intparam1,intparam2);

上面的例子中,每一行前面的那个*号,由编辑器自动添加,如果你的编辑器不会自动添加,可以不必添加。

6.3注释的修改

边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。

不再有用的注释要删除。

6.4尽可能使用尾部注释

示例:

voidClkUpdateTime(void)

{

if(ClkSec>=CLK_MAX_SEC)//Updatetheseconds

ClkSec=0;

if(ClkMin>=CLK_MAX_MIN)//Updatetheminutes

ClkMin=0;

if(ClkHour>=CLK_MAX_HOURS)//Updatethehours

ClkHour=0;

6.5注释的格式尽量统一

尾部注释建议使用“//”,头部使用块注释“/**/”

7.标识符命名约定

7.1一般约定

1、用#define或者const定义的符号常量所有字符都必须大写。

2、局部变量、成员变量和函数名采用驼峰规则,除第一个单词的首字母小写外,其它单词的首字母大写。

3、类名采用驼峰规则,所有单词首字母都要大写。

4、全局变量要以下划线作为首字符。

(但尽量不要使用全局变量)

5、所有用户自定义标识符尽量以有意义的单词组合作为名称。

6、循环计数器可以使用i,j,k这类短名称

7、指针类型以p开头。

7.2缩写与助记符

太长的单词可以使用缩写或者助记符形式,基本规则是取其中的3-4个字母,具体是:

1、首尾两个字母,中间取每个音节的首个字母(1-2个);

2、或者取最前面的3-4个字母;

3、一般不取元音字母;

4、如果已经有了公认的缩写形式,则以公认的形式为准,不受上面3条规则限制。

表3常用单词缩写表

单词

缩写

单词

缩写

Argument

Arg

Buffer

Buf

Clear

Clr

Clock

Clk

Compare

Cmp

Configuration

Cfg

Context

Ctx

Control

Ctl

Delay

Dly

Device

Dev

Disable

Dis

Display

Disp

Enable

En

Error

Err

Function

Fnct

Hexadecimal

Hex

HighPriorityTask

HPT

I/OSystem

IOS

Initialize

Init

Mailbox

Mbox

Manager

Mgr

Manual

Man

Maximum

Max

Message

Msg

Minimum

Min

Multiplex

Mux

OperationgSystem

OS

Overflow

Ovf

Parameter

Param

Pointer

Ptr

Previous

Prev

Priority

Prio

Read

Rd

Ready

Rdy

Register

Reg

Sehedule

Sched

Semaphore

Sem

Stack

Stk

Synchronize

Sync

Timer

Tmr

Trigger

Trig

Write

Wr

8.变量使用

1、尽可能少地定义全局变量;

2、局部变量与全局变量不要同名;

3、严禁使用未经初始化的变量作为右值;

9.函数设计和使用

9.1函数设计

1、明确函数功能,精确(而不是近似)地实现函数设计。

2、尽量不使用递归函数,尽可能从算法上消除递归,能用迭代的,坚决不能使用递归。

如果不能消除递归,则用自行管理堆栈的形式来消除形式上的递归。

3、函数的规模尽量限制在200行以内(不包括注释和空格行)。

4、一个函数执行一个任务或功能,一个复杂的功能可由多个功能单一的函数实现。

5、函数的功能是可以预测的,也就是只要输入数据相同就应产生同样的输出。

除非该函数已经明确表示使用了随机算法。

说明:

带有内部“存储器”的函数的功能是不可预测的,因为它的输出可能取决于内部存储器(如某标记)的状态。

这样的函数即不易于理解也不利于测试和维护。

6、尽量不要编写依赖于其他函数内部实现的函数。

此为函数独立性的基本要求。

7、如果多段代码重复做同一件事情,那么在函数的划分上可能存在问题。

说明:

若此段代码各语句之间有实质性关联并且是完成同一件功能的,那么可考虑把此段代码构造成一个新的函数。

8、功能不明确较小的函数,特别是仅有一个上级函数调用它时,应考虑把它合并到上级函数中,而不必单独存在。

说明:

模块中函数划分的过多,一般会使函数间的接口变得复杂。

所以过小的函数,特别是扇入很低的或功能不明确的函数,不值得单独存在。

9、设计高扇入、合理扇出(小于7)的函数。

扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,如总是1,表明函数的调用层次可能过多,这样不利程序阅读和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。

函数较合理的扇出(调度函数除外)通常是3-5。

扇出太大,一般是由于缺乏中间层次,可适当增加中间层次的函数。

扇出太小,可把下级函数进一步分解多个函数,或合并到上级函数中。

当然分解或合并函数时,不能改变要实现的功能,也不能违背函数间的独立性。

扇入越大,表明使用此函数的上级函数越多,这样的函数使用效率高,但不能违背函数间的独立性而单纯地追求高扇入。

公共模块中的函数及底层函数应该有较高的扇入。

10、函数除了有正常的返回值,也应该有表示出错情况的返回值。

如果二者不可兼得,应该使用异常机制。

9.2函数调用

1、对于所调用函数的错误返回码要仔细、全面的处理。

2、应明确规定对接口函数参数的合法性检查由函数的调用者还是由接口函数本身负责。

缺省是由函数编写者负责,除非函数内部无法判断参数的合法性(比如指针所指向的空间大小,这时调用者必须保证空间足够)。

3、非调度函数应减少或限制控制参数,尽量只使用数据参数。

说明:

本建议目的是防止函数间的控制耦合。

调度函数是指根据输入的消息类型或控制命令,来启动相应的函数,而本身并不完成具体功能。

控制参数是指改变函数功能行为的参数,即函数要根据此参数来决定具体怎样工作。

非调度函数的控制参数增加了函数间的控制耦合,很可能使函数间的耦合度增大,并使函数的功能不唯一。

示例:

如下函数构造不太合理

intadd_sub(inta,intb,unsignedcharadd_sub_flg)

{

if(add_sub_flg==INTEGER_ADD)

{

return(a+b);

}

else

{

return(a-b);

}

}

更好的做法是分为两个函数

intadd(inta,intb)

{

return(a+b);

}

intsub(inta,intb)

{

return(a+b);

}

4、在调用函数填写参数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换,因为数据类型转换或多或少存在危险(建议:

将编译器的所有警告开关全部打开,让编译器帮助发现此类危险)。

10.宏

可以使用宏来定义符号常量,但应该尽量减少用宏来定义表达式,切不可使用宏来代替函数。

定义表达式时,要使用完备的括号。

11.头文件

11.1防止重复包含

为防止重复包含,请在头文件加上条件INCLUDE。

示例:

#ifndef__LINUX_FILE_H

#define__LINUX_FILE_H

#include

#include

#include

#endif

11.2仅引用需要的头文件

当模块的实现依赖于其他模块时,要这样做:

尽量在C/C++源文件手工引用多个头文件,仅引用你需要调用的头文件。

而不要这样做:

把多个头文件包含在一个头文件中,源文件仅包含这一个头文件。

12.可测性

12.1调试信息的控制

要有一套统一的为集成测试与系统联调准备的调测开关及相应打印函数,并且要有详细的说明。

示例,以下使用DEBUG作为调试开关,输出调试信息

#ifdefDEBUG

#defineDPRINTF(s)PRINTF(s)

#else

#defineDPRINTF(s)

#endif

如果要将调试开关打开,只需要传递给编译器”-DDEBUG”的标记。

测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过调测开关)。

12.2调试信息的格式

调测打印出的信息串的格式要有统一的格式。

信息串中至少要有所在模块名(或源文件名)及行号。

说明:

统一的调测信息格式便于分析,特别是用程序来辅助分析。

12.3使用断言

断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告),它可以快速发现并定位软件问题,同时对系统错误进行自动报警。

断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。

实际应用时,可根据具体情况灵活地设计断言。

正式软件产品中应把断言及其他调测代码去掉(即把有关的调测开关关掉)。

在软件系统中设置与取消有关测试手段,不能对软件实现的功能等产生影响(即有测试代码的软件和关掉测试代码的软件,在功能行为上应一致)。

13.质量保证

13.1代码质量保证优先原则

1、正确性,指程序要实现设计要求的功能。

2、稳定性、安全性,指程序稳定、可靠、安全。

3、可测试性,指程序要具有良好的可测试性。

4、规范/可读性,指程序书写风格、命名规则等要符合规范。

5、全局效率,指软件系统的整体效率。

6、局部效率,指某个模块/子模块/函数的本身效率。

7、个人表达方式/个人方便性,指个人编程习惯。

13.2只引用属于自己的存贮空间

若模块封装的较好,那么一般不会发生非法引用他人空间的情况。

13.3防止引用已经释放的内存空间

在实际编程过程中,稍不留心就会出现在一个模块中释放了某个内存块(如C语言指针),而另一模块在随后的某个时刻又使用了它。

要防止这种情况发生,除了多测试,别无办法。

13.4防止内存泄漏

函数中分配的内存,在函数退出之前要释放。

用malloc函数分配的内存,要用free释放;用new分配的内存,要用delete释放。

为了最大程度上避免内存泄漏的出现,推荐:

1、如果动态申请的内存只在本函数内使用,请使用向量vector来操作。

2、如果需要全局使用或者跨函数使用动态内存,请使用模板类auto_ptr。

但不管使用何种方法,程序编写成功后,还需要利用第三方工具进行跟踪测试。

13.4防止内存操作越界

内存操作主要是指对数组、指针、内存地址等的操作。

内存操作越界是软件系统主要错

误之一,后果往往非常严重,所以当程序进行这些操作时一定要仔细小心。

为了防止指针越界,应该尽量少使用指针,如果仅仅是为了使用连续的内存空间,完全可以用vector来代替。

如果定义二级指针是为了处理字符串数组,可以直接使用string数组。

为了防止下标越界,需要在使用前进行下标合法性检测,更省事的方法是用vector代替C++的原生数组。

13.5提高程序健壮性

1、程序员需要认真处理程序所能遇到的各种出错情况。

2、系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用;

3、要对加载到系统中的数据进行一致性检查;

4、编程时,不能随心所欲地更改不属于自己模块的有关设置如常量、数组的大小等。

5、严禁随意更改其它模块或系统的有关设置和配置。

6、不能随意改变与其它模块的接口。

7、编程时,要防止“差1”错误。

此类错误一般是由于把“<=”误写成“<”或“>=”误写成“>”等造成的,由此引起的后果,很多情况下是很严重的,所以编程时,一定要在这些地方小心。

当编完程序后,应对这些操作符进行彻底检查。

8、要时刻注意易混淆的操作符。

当编完程序后,应从头至尾检查一遍这些操作符,以防止拼写错误。

形式相近的操作符最容易引起误用,如C/C++中的“=”与“==”、“|”与“||”、“&”与“&&”等,若拼写错了,编译器不一定能够检查出来。

9、系统应具有一定的容错能力,对一些错误事件能进行自动补救。

13.6多线程

编写多线程程序,尽量使用VC提供的线程类。

凡是可能有多个线程访问的变量或者资源,一定要用临界区进行保护。

尽量不要用线程去访问界面,因为MFC的界面类都不是线程安全的。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1