编程规范1、程序员花更多的时间在调试、维护和升级已有代码上,而不是编写新的代码;2、程序最重要的是正确性,其次是可维护性,最后才是效率;3、学习如何写优美的程序与学习如何正确地编写代码同样重要;4、让程序尽量简单易懂,即使违背了某些规则也无关紧要;5、一个运行正常但没有注释的程序如同一个等待爆炸的定时炸弹,因为早晚会有人修改或升级这个程序;6、好风格应该成为一种习惯。如果你在开始写代码时就关心风格问题,如果你花时间去审视和改进它,你将会逐渐养成一种好的编程习惯。一旦这种习惯变成自动的东西,你的潜意识就会帮你照料许多细节问题,甚至你在工作压力下写出的代码也会更好。关于编程规范的几个原则floatb,c[10];voidabc(void){floatzongfen=0;intd;for(d=0;d10;d++){if(c[d]0)zongfen+=c[b];b=zongfen/10;}这段程序在做什么?这段程序是否有错误?这程序中存在哪些不良的书写风格?它们可能会引起什么后果?程序实例floatb,c[10];voidabc(void){floatzongfen=0;intd;for(d=0;d10;d++){if(c[d]0)zongfen+=c[b];b=zongfen/10;}#defineSTUDENT_NUM10//学生总数floatfAvgScore;//平均分floatfScore[STUDENT_NUM];//分数/*平均分计算函数*/voidAvgScore(void){inti;floattotal_score=0;//总分for(i=0;iSTUDENT_NUM;i++){//累加计算总分if(fScore[i]0)//遇到负分,记为0分total_score+=fScore[i];}//计算平均分if(STUDENT_NUM0)fAvgScore=total_score/STUDENT_NUM;}有了哪些改进?你认为还有什么地方需要改进?一、标识符标识符的命名要清晰、明了,有明确含义。使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。标识符应当采用英文单词或其组合,切忌使用汉语拼音来命名。坏的命名:inta/Age1/XueshengAge;好的命名:intStudentAge;1.1变量名1.1.1不同作用域变量的命名局部变量以小写字母命名;全局变量以首字母大写方式命名(骆驼式);定义类型和宏定义常数以大写字母命名;变量的作用域越大,它的名字所带有的信息就应该越多。局部变量:intstudent_age;全局变量:intStudentAge;宏定义常数:#defineSTUDENT_NUM10类型定义:typedefINT16Sint;1.1.2不同类型变量的命名(匈牙利命名法)匈牙利命名法是一种命名约定。匈牙利命名法把变量的类型(或者它的预期使用)等信息编码在变量名中。一些常用的匈牙利命名法前缀数据类型前缀例子charccInCharunsignedcharucucOutCharintiiReturnValueunsignedintuiuiControlWordlongllNumRecsfloatffLengthdoubleddArea一、标识符1.1.3指针变量的命名对于指针的定义,名称大小写根据指针为全局/局部变量来定,但指针名必须以小写的“p”开头。如:int*pDay;//全局指针int*pday;//局部指针int**ppDay;//指针的指针1.1.4在某一模块中使用的变量,变量名的开始需有模块名。如:模块KEY.C中的变量:intiKeyNum;intiKeyNumBuff[10];一、标识符一、标识符1.2函数名函数名的命名应象全局变量一样采用首字母大写方式(骆驼式)。函数名的开始应以“模块名_”的格式注明函数所属模块。例如:(1)KEY.C模块的函数voidKEY_Init(void);voidKEY_StartScan(void);voidKEY_StopScan(void);(2)TMR.C模块的函数voidTMR_Init(void);voidTMR_Start(TMR_IDtmr);voidTMR_Stop(TMR_IDtmr);二、排版名字的合理选择可以帮助理解程序。同样,也应该以尽可能一目了然的形式书写语句。这就像保持书桌整洁可以使你容易找到东西一样。2.1用缩进格式书写代码函数或过程的开始、结构定义及循环、判断等语句中的代码都要采用缩进;缩进的空格数为4个;使用空格键,不使用TAB键;程序块的分界符(‘{’和‘}’)应各独占一行。例:for(i=0;iSTUDENT_NUM;i++){//累加计算总分if(fScore[i]0){//遇到负分,记为0分total_score+=fScore[i];}}二、排版2.2其他书写格式2.2.1长语句较长的语句(多于80字符)要分成多行书写;长表达式要在低优先级操作符处划分新行,操作符放在新行之首;划分出的新行要进行适当的缩进,使排版整齐,语句可读;不允许把多个短语句写在一行中,即一行只写一条语句。例:修改前:MeasData.TransT[dir]=TransT[dir]*SetData.Filter+TransT[dir]*(1-SetData.Filter);修改后:MeasData.TransT[dir]=TransT[dir]*SetData.Filter+TransT[dir]*(1-SetData.Filter);二、排版2.2.2空行和空格的使用相对独立的程序块之间、变量定义之后语句开始以前必须加空行;逗号、分号只在后面加空格;比较操作符、赋值操作符、算术操作符、逻辑操作符、位域操作符等双目操作符的前后加空格;“!”、“~”、“++”、“--”、“&”等单目操作符前后不加空格;-、.前后不加空格。例:voidFunc1(intx,inty,intz);//良好的风格voidFunc1(intx,inty,intz);//不良的风格x=ab?a:b;//良好的风格x=ab?a:b;//不好的风格int*x=&y;//良好的风格int*x=&y;//不良的风格三、表达式和基本语句3.1运算表达式不要编写太复杂的复合表达式;例如:i=a=b&&cd&&c+f=g+h;//复合表达式过于复杂不要有多用途的复合表达式;例如:d=(a=b+c)+r;//应拆分为两个语句:a=b+c;d=a+r;如果代码行中的运算符比较多,用括号确定表达式的操作顺序,避免使用默认的优先级。例如:if(a|b&&a&c)//不良的风格if((a|b)&&(a&c))//良好的风格注意:只需记住加减运算的优先级低于乘除运算,其它地方一律加上括号。三、表达式和基本语句3.2if语句3.2.1布尔变量与零值比较不可将布尔变量直接与TRUE、FALSE或者1、0进行比较。根据布尔类型的语义,零值为“假”(记为FALSE),任何非零值都是“真”(记为TRUE)。TRUE的值究竟是什么并没有统一的标准。例如VisualC++将TRUE定义为1,而VisualBasic则将TRUE定义为-1。例:假设布尔变量名字为flag,它与零值比较的标准if语句如下:if(flag)//表示flag为真时满足条件if(!flag)//表示flag为假时满足条件其它的用法都属于不良风格,例如:if(flag==TRUE)if(flag==1)if(flag==FALSE)if(flag==0)3.2.2整型变量与零值比较应当将整型变量用“==”或“!=”直接与0比较。例:假设整型变量为value,它与零值比较的标准if语句如下:if(value==0)if(value!=0)不可模仿布尔变量的风格而写成if(value)//会让人误解value是布尔变量if(!value)3.2.3浮点变量与零值比较不可将浮点变量用“==”或“!=”与任何数字比较。千万要留意,无论float还是double类型变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“=”或“=”形式。假设浮点变量的名字为x,应当将if(x==0.0)//隐含错误的比较转化为if((x=-EPSINON)&&(x=EPSINON))//EPSINON是精度三、表达式和基本语句三、表达式和基本语句3.2.3对if语句的补充说明有时候我们可能会看到这样古怪的格式:if(NULL==p)不是程序写错了,是有经验的程序员为了防止将if(p==NULL)误写成if(p=NULL),而有意把p和NULL颠倒。编译器认为if(p=NULL)是合法的,但是会指出if(NULL=p)是错误的,因为NULL不能被赋值。三、表达式和基本语句3.3switch语句每个case语句的结尾不要忘了加break,否则将导致多个分支重叠(除非有意使多个分支重叠)不要忘记最后那个default分支。即使程序真的不需要default处理,也应该保留语句default:break;这样做并非多此一举,而是为了防止别人误以为你忘了default处理。switch语句的标准格式是:switch(variable){casevalue1:…break;casevalue2:…break;…default:…break;}四、常量这是一个根据LCD的列来计算像素X坐标的函数:INT16ULCD_GetStX(INT8Ucol){INT16Ux;if(col29)col=29;#ifLCD_MODE==_VGAx=150+(INT16U)col*8;#elifx=(INT16U)col*8;#endifreturn(x);}代码中的数(29,8,150)都是什么意义?这些神秘的数给程序的阅读和维护增加了很大的难度。#defineLCD_MAX_COL29//LCD最大列数#defineLCD_START_X150//LCD起始X坐标#defineLCD_COL_WIDTH8//LCD列宽INT16ULCD_GetStX(INT8Ucol){INT16Ux;if(colLCD_MAX_COL)col=LCD_MAX_COL;#ifLCD_MODE==_VGAx=LCD_START_X+(INT16U)col*LCD_COL_WIDTH;#elifx=(INT16U)col*LCD_COL_WIDTH;#endifreturn(x);}四、常量四、常量4.1为什么要用常量如果不使用常量,直接在程序中填写数字或字符串,将会有什么麻烦?(1)程序的可读性(可理解性)变差。程序员自己会忘记那些数字或字符串是什么意思,用户则更加不知它们从何处来、表示什么。(2)在程序的很多地方输入同样的数字或字符串,难保不发生书写错误。(3)如果要修改数字或字符串,则会在很多地方改动,既麻烦又容易出错。4.2定义常量的方法(1)#define宏定义(2)const常量(3)enum枚举4.3#define宏定义使用最广泛,如:#defineMAX_TEACHER100缺点:宏定义的常量没有类型,只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。4.4const常量如:constintMAX_STUDENT=100;优点:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。缺点:const常量无法在数组定义时作为数组长度。如:floatStudentHeight[MAX_STUDENT];//错误四、常量4.5枚举enum{RED,BLUE,GREEN,YELLOW,WHITE,BLACK,COLOR_NUM};优点:(1)适合一次定义批量常数,尤其是在数值连续时尤为方便;(2)枚举常量可以作为数组长度,如:floatBallSize[COLOR_NUM];缺点:不能定义除整型