2020年2月25日1C语言代码规范2020年2月25日2主要内容表达式类型和数据函数控制状态内存分配文件组织布局和风格命名注释其他2020年2月25日3为什么需要代码规范增强可读性减少错误提高可维护性增加可移植性增强可配置性方便调试为测试工具的验证提供必要条件2020年2月25日4表达式在表达式中避免副作用–不好的例子if(((left=(1(idx1=len-wid)))(idx2=max-min))&&((right=idx3++)=limit)){...}2020年2月25日5表达式在表达式中避免副作用–好的例子idx1=len-wid;idx2=max-min;left=1idx1;if(leftidx2){right=idx3++;if(right=limit){...}}2020年2月25日6表达式在表达式中使用括号来清晰地分隔子表达式–不好的例子result=a+b*cd/2&e;–好的例子result=((a+(b*c))(d/2))&e;2020年2月25日7表达式在if,while和for语句中,只能使用布尔控制表达式。如果表达式不是一个逻辑表达式,使用一个明确的测试。–例子:WORD16i;BYTE*a_ptr;/*不好的表达式好的表达式*/while(i)...while(i!=0)...for(i=10;i;i--)...for(i=10;i0;i--)...if(!a_ptr)...if(a_ptr==0)...2020年2月25日8表达式在逻辑表达式中不要使用位操作–好的例子voidsome_function(){BOOLbMsgReceived;WORD32dwStatus;BOOLbBitSet;bBitSet=dwStatus&dwBitMask;/*(1)*/if(bMsgReceived&&bBitSet)/*(2)*/{...}}2020年2月25日9表达式保证在表达式中的操作符计算顺序没有任何影响。特别对那些有副作用的子表达式。–不好的例子a[i]=i++;/*不允许使用(1)*/a=b+f(&b)/*不允许使用(2)*/–好的例子/*(1)*/a[i]=i;i++;/*(2)*/help=b;a=help+f(&b);2020年2月25日10表达式在一条语句中不要多次改变一个变量/对象–不好的例子WROR32i=0;WORD32*pdwPtr=&i;i=i+(*pdwPtr)++;2020年2月25日11类型和数据整个程序中,常量,变量或函数的定义和以及它们在外部连接种的声明采用相同的类型。不要使用本地的类型声明和定义它们。–不好的例子:srcfile1.cCharstring[]=samenames,butnon-matchingtypes;srcfile2.cexternChar*string;.../*修改了一个常量指针,编译器不能够发现这个错误,链接器也可能无法检查对常量的修改*/string++;2020年2月25日12类型和数据当extern,volatile,static,auto,register这些数据在声明和定义中使用时,把它们放置在一行的开始。在声明和定义中必须使用类型说明。在函数的开始放置声明和定义。建议:在定义语句中初始化每一个变量。2020年2月25日13类型和数据建议:尽量避免全局常量和变量。如果常量,变量和函数只在一个代码模块中使用,应该使用static。–坏的例子:srcfile1.cWORD32temp_var;/*(1)*/...srcfile2.cWORD32temp_var;/*(2)*/...temp_var++;/*(3)*/2020年2月25日14类型和数据只使用在项目级别定义的类型别名,而不能使用c定义的类型名(除了void,enum)。特别对于那些具有整数意义的类型,特别对于char,signedchar,unsignedchar,short,unsignedshort,int,unsigned,long,unsignedlong。–声明WORD32a比声明unsignedlonginta具有更强的移植性和可读性。2020年2月25日15类型和数据在编写代码时,不要假设数据类型的实例在内存中是如何存放的。2020年2月25日16数据和类型使用typedef为整数和浮点类型指示意义的定义,以增强可读性和维护性。–好的例子:typedefWORD16Color_type;typedefWORD16Temperature_type;Color_typefunc1(){Color_typeactual_color;...returnactual_color;}2020年2月25日17数据和类型使用unsigned的整数类型定义那些没有负值的变量对字符类型明确使用signed或者unsigned如果使用ASCII,明确使用unsigendchar对enum进行比较时,只是用相同定义的enum类型在switch…case中,switch和case使用相同的enum类型2020年2月25日18数据和类型明确使用检查以避免除零和模零如果操作数具有不同的符号类型,使用标准库中的div和ldiv代替除法和模操作符。2020年2月25日19数据和类型只对unsigned类型使用移位移位的计数必须大于等于0,小于被移位数的长度2020年2月25日20数据和类型不要使用移位操作来代替以2位指数的乘法和除法不要使用‘&’来代替模操作2020年2月25日21数据和类型在程序关键的地方进行充分的检查,以避免和检测数据的上溢和下溢2020年2月25日22数据和类型在对两个浮点数计进行比较时,不能使用直接的比较:==或者!=,只使用合适的估计范围。2020年2月25日23数据和类型必须避免隐含定义的类型转化–不好的例子在SPARCC++4.1的编译平台上有以下的结果:signedlonga=0x7FFFFFFFL;signedintb=a;/*b=2147483647*/unsignedintc=a;/*c=2147483647*/signedshortd=a;/*d=-1*/usignedshorte=a;/*e=65535*/signedcharf=a;/*f=-1*/unsignedcharg=a;/*g=255*/unsignedshorth=0xFFFF;signedshourti=h;/*i=-1*/2020年2月25日24数据和类型在混合使用有符号和无符号类型时,必须谨慎。–好的例子:unsignedshortus=4;signedintsi=-9;signedintsi_res;si_res=si+us;–不好的例子:unsignedshortus=4;signedintsi=-9;BOOLbool_res;bool_res=(si+us)3;2020年2月25日25数据和类型不要依赖于数据长度(或者类型转化)来对一个比特数进行裁减。必须坚持使用掩码(mas)。建议:尽量减少强制类型转化2020年2月25日26数据和类型不要把一个const转化为非const2020年2月25日27数据和类型建议:把一个类型的指针转化为另外一个类型的指针时,必须小心。不要把一个指针转化为非指针对象,反之亦然(除了少量底层代码)。不要把指向函数的指针转化为任何其他类型的对象,反之亦然。2020年2月25日28数据和类型建议:尽量使用const(const数据和参数)–例子:/*指向常量字符串的指针;指针可以改变,但是字符传不能改变*/constunsigned*ptr_to_const_obj=abcd;*(ptr_to_const_obj+2)='C';/*error*/ptr_to_const_obj=ABCD;/*correct*//*指向字符串的常量指针;字符串可以改变,但是指针不行*/unsignedchar*constconst_ptr_to_obj=abcd;*(const_ptr_to_obj+2)='C';/*correct*/const_ptr_to_obj=ABCD;/*error*//*指向常量字符窜的常量指针;它们都不可以改变*/constunsignedchar*constconst_ptr_to_const_string=abcd;(const_ptr_to_const_string+2)='C';/*error*/const_ptr_to_const_string=ABCD;/*error*/2020年2月25日29数据和类型建议:使用const或者enum定义常量,减少#define的是有使用–好的例子:enum{max_size=1000};voidfunc(void){unsignedintsome_array[max_size];constunsignedintlower_limit=0;constunsignedintupper_limit=max_size;unsignedintindex;for(index=lower_limit;indexupper_limit;index++){…}}2020年2月25日30数据和类型不要使用神秘数,必须使用具有意义的值代替。不能修改字符串常量。如果需要使用可以修改的字符串,必须使用数组。2020年2月25日31数据和类型不要对指针使用操作符!,&&,,||,不要对两个指针使用加法。对相同的数组使用比较和减法。2020年2月25日32数据和类型建议:减少指向指针的指针,以免降低程序的可读性。2020年2月25日33数据和类型当声明函数指针式,使用typedef–好的例子:unsignedintstr_cmp(char*,char*);/*函数原型*/unsignedintnum_cmp(char*,char*);/*函数原型*//*新的数据类型Pointer_to_comparefunction:指向一个函数,它具有两个char*参数,并返回unsignedint的结果*/typedefunsignedint(*Pointer_to_comparefunction)(char*,char*);Pointer_to_comparefunctionstr_cmp,num_cmp;/*quicksort使用了这个新定义的数据类型*/voidquicksort(Pointer_to_comparefunction,otherarguments);如果不使用新的数据类型定义,则可读性不强:voidquicksort(unsignedint(*cmp_ptr)(char*,char*),otherarguments);2020年2月25日34数据和类型对多维数组只使用下标记号–例子:WORD32x[5][30];WORD32i;i=x[2][7];/*OK*/i=*(*(x+2)+7);/*BAD*/2020年2月25日35数据和类型函数蚕室不要声明为数组,只是用指针标记。2020年2月25日36函数避免函数参数个数,通常来说6个以上的参数就可以被视为不合理。2020年2月25日37函数在函数原型中定义参数名字,并且和函数定义中的相同。2020年2月25日38函数建议:不要在用户定义的函数中使用可变长的参数列表。建议:减少定义带有void*的参数和/或返回void*值的函数。2020年2月25日39函数如果函数返回非void类型的结果,必须在任何函数可能返回的地方使用明确地带有表达式的return语句。–不好的例子:WORD32some_function(WORD32i,WORD32j){if(i==1){return1;}else{if(j==1){return0;}}/*returnmissingher