在编写程序的过程中,特别是在多人协作编程时,规范的程序书写格式可以提高程序的可读性,提高编写程序的效率,使写出的程序具有更高的可移植性。本公司在多年的软件开发过程中,总结了许多使程序更加清晰可读的规则,逐步形成了自己的一套编程风格。全面的了解和熟悉这些规则,并在实际编程中严格的遵守这些规则,对每一位编程人员来说都是非常重要的。 以下是在编程过程中应该遵循的规则: 一、基本要求 1.1 文件名(不包括扩展名)的长度不超过8个字符,即尽量不用长文件名。 1.2 Tab键一般设为8,Tab字符要存成空格。 1.3 一般来说,类、结构、枚举的定义,函数的声明放在.h中, 1.4 函数、成员函数的实现放在.cpp中,不要把它们放在.h中。(inline函数除外) 1.5 缩格 语句缩进为两个字符。例如: if(i == 10) Value = 10; 1.6 列对齐 一般来说,需要对齐书写的列都从第8n+1列开始书写。 一个文件中需要对齐书写的列尽量从同一列开始书写。 1.7 局部变量尽量在要用到的地方定义,不要全部定义在文件的开头。 1.8 在设计数据结构时要遵守对齐原则 编译选项中要选4字节靠齐,代码书写时要按8字节靠齐书写。 当有字节空出时,要用Rev标明,以便再需要空间时首先使用此空间。 例如: struct StructA { BYTE A; BYTE Rev[3]; DWORD C; } 1.9 #include "headerfile.h"的书写 头文件的include要按相同的顺序书写。 在所有文件都要include的头文件写完后,要用#inclde hdrstop标识出来。 例如: a.cpp中b.cpp中 #include <windows.h>#include <windows.h> #pragma hdrstop#pragma hdrstop #include <stdio.h>#include <stdio.h> #include <io.h>#include <string.h> ...... 二、程序框架 这里说的程序框架,是指为了体现程序结构,以注释的形式对源文件按功能进行模块的划分。 具体方法: 2.1 模块命名 模块名应有意义,可以明确表示模块的功能。 如果一个模块只是一个类的话,模块名应为"class 类名"。例如:class BaseWND 2.2 模块声明 在预处理之后列出所有定义的模块名。 模块名应缩格书写,如果模块中还定义了子模块,子模块名要相对其父模块缩格书写。 例如: /*(顶格书写) Module1 Name (缩格书写) Module2 Name Child Module Name (缩格书写) ……… ……… */ 2.3 模块的定义 在模块的起始/结束位置以模块名加Begin/End的方式标明。格式如下: // Module1 Name Begin ...... (Module1) // Module1 Name End 2.4 cpp文件中模块的声明和定义必须同时写出,而在h文件中如果模块只是一个类时,可以只写声明部分。 2.5 入口(Import):即模块中使用到的其它模块定义的函数,这些函数可能被改动。 2.6 出口(Export):即供其它模块使用的函数。 三、注释 3.1 注释符号与程序代码放在同一行时,应该用一个以上的空格和程序代码分开。 3.2 "//"与注释文字之间要空一格。 3.3 使用"//"的注释应该尽量列对齐书写。 3.4 不易看懂的部分一定要注释。 四、命名 4.1 应该使用有具体意义的名字进行命名,这样可以减少注释。 4.2 变量名和函数名一律按XxxXxx格式书写。除循环变量外,单个字母的变量也要用大写字母表示。 例如:MaxItems、M 4.3 循环变量可以使用单个小写字母来命名。例如: for(int i = 0; i < 10; i++) Array[i] = 0; 4.4 预处理宏名字中的所有字母都应大写,中间可以用"_"分隔,即使用XXX_XXX格式。 常量宏、变量宏的定义都用这种方法。如常量MAX_PATH、PI 4.5 类名、结构名、枚举名一律按XxxXxxXXX格式书写。 如果仅由一个单词组成,则整个单词大写(XXX格式)。例如:CreateFontINFO 4.6 只有下列数据类型的变量名加前缀,其它类型不加前缀: 前缀p:指针型变量名; 前缀h:句柄型变量名; 前缀b:布尔型变量名。 4.7 类成员变量和函数不能另外加前缀。 4.8 函数的参数命名不用in/out来标识传入/传出。 五、表达式 5.1 需要判断优先级的表达式,要用"()"来标明不同的优先级,以便程序的阅读。 5.2 当表达式太长,一行写不下时(超过80个字符),应把它分为几行书写。 5.3 划分表达式的基本规则如下: 在一个低优先级的操作符后开始划分。 把这个操作符后的放到新行上。 使新的一行相对于语句的第一行缩格。 如果表达式要分为3行以上,则从第3行始的每一行与第2行对齐。 例如: Value = TheDatabase.Search(UserQuery->Criterium, CurrentSession.Domain, ...); 5.4 划分用小括号括起的表达式时,也可以让新行与"("后的内容对齐书写。例如: Value = TheDatabase.Search(UserQuery->Criterium, CurrentSession.Domain); 5.5 划分赋值表达式时,也可以让新行与"="后的内容对齐书写。 Value = MaxNumber(Number1, Number2) - MinNumber(Number3, Number4); 5.6 如果表达式包含函数调用,应在尽量在函数调用以外的地方划分它,以保证函数调用的完整性。 除非函数的调用部分很长,必须划分。 例如:上例中不要按以下方式划分 Value = MaxNumber(Number1, Number2) - MinNumber(Number3, Number4); 5.7 划分条件表达式时,新的一行与表达式的开始位置同列。例如: if(Condition == Green && Status == Ok) GrantClearancce(); 六、 语句 6.1 基本规则 6.1.1 表达式中不允许出现连续的两个空格。 6.1.2 在","与";"符号的左边不能有空格,但右边要空格。例如: for(int i, j = 0; i > 4; i++) Array[i][j] = 0; 6.1.3 二维算数运算符、关系运算符的左右要各空一格。 但如果其中一个操作数是很小的数字时,不要空格。例如: Sum = Number1 + Number2; Sum = Number+5; 6.1.4 一维运算符与操作数之间不要空格。例如:i++ 6.1.5 间接访问运算符"*"和取地址运算符"&",右边不空格。 它们与左边的数据类型后之间要空格。例如: void Function(char *pString, int &Num); Function(&Buffer, Number); 有"*"、"&"的变量定义及声明的列对齐方式如下例所示: int Num; char *pStr; int &Value; 6.1.6 “箭头”运算符"->"的左右都不要空格。 6.1.7 域操作符"::"的左右都不要空格。 6.1.8 数组名与其后的"["之间不要空格。例如:Array[3] 6.1.9 大括号使用规则 使用大括号"{"和"}"时,把它们分别放在单独的一行上,以提高程序的可读性。 大括号与引用它的语句对齐。而大括号中的正文应该缩格书写。例如: while(GetMessage(&Msg, NULL, 0, 0)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } 6.1.10 连续书写的语句不要超过10行,要在适当的地方空一行。 6.1.11 不同用途的语句之间要适当的空一行。 6.1.12 占多行的语句前后都要空一行。 6.1.13 每次空行不要超过一行。 6.1.14 尽量把常量的定义放在一起书写。 6.1.15 预处理部分放在源程序的开始。例如: #include <windows.h> 6.1.16 预处理指令分为多行时,每行后的"\"应列对齐书写。 #define GET_MAX_NUM(A, B) \ if(A > B) \ Ret = A; \ else \ Ret = B; 6.1.17 if、while、for、do-while、switch、case等语句的语句体另起一行,用大括号括起。 按大括号的使用规则书写。 6.1.18 if、while、for语句中,如果语句体只有一条语句可以不加大括号。 6.1.19 语句体要缩格书写。 6.1.20 语句关键字与其后的"("之间,不能有空格。 6.1.21 语句尽量精简,可写可不写的部分不要写。例如: return (Ret); 应写为 return Ret; 语句后的表达式可以用小括号将其整个括起,也可以不写这对小括号,此时要求不写小括号。 6.1.22 数组的定义 数组定义在一行时,数组内容与"{","}"之间要空一格。"="与"{"之间也要空一格。例如: int Array[] = { 1, 2, 3 }; 数组内容较多需分多行书写时,第一行从"="后开始划分, 具体内容另起一行缩格书写,其它行从","后开始划分,内容之间对齐书写, "{","}"占单独的一行。例如: char Array[][20] = { "String1", "String2", "String3", "String4" }; 6.1.23 Goto语句尽量少用。 6.2 for语句 6.2.1 在for语句的表达式中,分号的右边要空一格。 6.2.2 划分for语句的表达式时,应尽可能的在for语句中的分号位置后划分。 6.2.3 划分for 语句的时候,如果只有第二个表达式很长,可以只划分二个表达式,将语句写成两行。例如: for(i = 0; i < ARRAYSIZE && Status == Ok && ResourceLever > MinResourcelLevel; i++) Array[i] = i; 6.3 do-while语句 6.3.1 do-while语句中,左括号"{"单独占一行,而右括号"}"应与while条件语句在同一行上。 6.3.2 "while"与前面的"}"之间,必须空一格。 例如: do { Value++; } while(i < 10); 6.4 switch语句 6.4.1 "case"与其后的值之间,必须有一个空格,值与":"之间不能有空格。 6.4.2 case语句相对于switch要缩格。case语句体相对于case要缩格。 6.4.3 case语句体如果很简单,可以不使用大括号。例如: switch(Month) { case 1: case 2: { Value = 5; ... break; } case 12: Value = 7; break; default: { ... } } 七、函数 7.1 一个函数不要过大,如果函数太大,尽量把其按功能划分为几个小函数。 7.2 具有类似功能的函数要放在一起书写,可以把它们作为一个模块。 7.3 函数之间要空一行。 7.4 函数的返回类型与函数名写在同一行。 7.5 函数名与其后的"("之间不能空格。 7.6 函数定义中,参数的类型说明在参数表中完成。 7.7 函数参数表中,各参数之间的逗号后要空一格。 7.8 函数参数表中的指针,如果只用于传入时,一定要加const。 7.9 函数定义中,语句体要另起一行,用大括号括起。 7.10 语句体要缩格书写。 7.11 函数定义中,如果语句体为空或者为单个简单语句,可将语句体与函数名放在同一行,"{"前要空一格,语句体前后也要空一格。如果语句体为空,"{"和"}"之间不空格。 7.12 在定义或调用一个函数时,如果参数很长,可以在一个参数之后划分它。 7.13 划分函数的参数时,不要把某个参数的类型和标识符分开放在不同行上。 7.14 划分函数的参数时,另起的一行从函数定义的第一个参数所在列开始,或缩格书写。例如: BOOL CALLBACK DialogProc(HWND hDlg, UINT Msg, WPARAM WParam, LPARAM LParam); BOOL CALLBACK DialogProc(HWND hDlg, UINT Msg, WPARAM WParam, LPARAM LParam); 7.15 划分函数时,也可以将整个参数表另起一行,新行与函数的起始位置对齐。 BOOL CALLBACK DialogProc (HWND hDlg, UINT Msg, WPARAM WParam, LPARAM LParam); 八、类和结构 8.1 类和结构的定义中,语句体要另起一行,用大括号括起。 8.2 语句体要缩格书写。 8.3 类名和基类之间的":"左右都要空一格。 8.4 类和结构的定义中,成员及成员函数名要对齐书写。 8.5 类和结构的定义中,private,public,protected关键字单独占一行,并且不要缩格。 例如: class ExamplePOS : public BasePOS { private: double X; double Y; public: init(double Xc = 0.0, double Yc = 0.0); char *Display(); double GetSum() { return X + Y; } }; 8.6 能不写struct,class关键字的地方就不写,例如: class MyCLASS Test; 应写为 MyCLASS Test; 8.7 ":"左右各空一格,如果要划分表达式,应从":"后开始划分,并缩格书写。例如: MyCLALL::Func(int A, int B) : BaseFunc(int A, int B) { ... }
|