分类: C/C++
2009-10-13 11:13:37
C语言编码规范
1.文件结构(4条规则+6条建议)
C程序文件通常分为两类文件:
一类文件用于保存程序的声明(declaration),称为头文件。头文件以“.h”为后缀。
另一类文件用于保存程序的实现(implementation),称为定义(definition)文件。定义文件以“.c”为后缀。对于简单的C语言程序,一般在把头文件和程序定义文件放在一起,只有一个.c定义文件即可。而对于复杂的程序,则多采用头文件包含的形式并通过多个定义文件实现。
1.1 版权和版本的声明
版权和版本的声明一般应该位于头文件和定义文件的开头(参见示例1-1),主要内容包括:
(1)版权信息;
(2)文件名称、文件标识、摘要;
(3)当前版本号、作者/修改者、修改日期、修改描述等;
(4)版本历史信息、原作者、完成日期等。
/* * Copyright (c) 2008 * All rights reserved. * * 文件名称:filename.h * 文件标识:根据软件工程设置 * 摘要:简要描述本文件的作用和内容等 */ //下面其它的声明代码 … //下面是原作者、版本、完成、日期和当前版本的信息 /* 当前版本: * 作者:修改者名字,修改日期: * 修改的地方描述: */ /* * 取代版本: * 原作者:原作者名字,完成日期: */ |
示例1-1 版权和版本的声明
版本标识:采用<主版本号>.<次版本号>.<修订号> 来命名自己产品的编号。一般这样约定,如果次版本号是偶数(如0、2、4等),代表正式版本,如果次版本号是奇数(如1、3、5等),代表开发过程中的测试版本。修订号则相当于Build号,用来标识一些小的改动。
1.2 头文件的结构
头文件由三部分内容组成:
(1)文件开头处的版权和版本声明(参见示例1-1);
(2)预处理块;
(3)声明函数原型和声明数据结构或变量等。
假设头文件名称为filename.h,头文件的结构参见示例1-2。
/* * Copyright (c) 2008 * All rights reserved. * * 文件名称:filename.h * 文件标识:根据软件工程设置 * 摘要:简要描述本文件的作用和内容等 */ #include #include #include struct studentstruct { int no; char name[20]; char sex; float score; }; void GetValue() { } void SetValue(int no) { } //后面同示例 1-1。 |
示例1
1.3 定义文件的结构
定义文件有三部分内容:
(1)定义文件开头处的版权和版本声明(参见示例1-1);
(2)对一些头文件的引用;
(3)程序的实现体(包括数据和代码)。
假设定义文件的名称为filename.c,定义文件的结构参见示例1-3
/* 版权和版本声明见示例1-1,此处省略。*/ #inlcude “filename.h” #ifndef GRAPHICS_H // 防止graphics.h 被重复引用 #define GRAPHICS_H /* 函数的实现体*/ void GetValue() { … } /* 函数的实现体*/ void SetValue(int no) { … } void main() { … } |
示例1
1.4头文件和定义文件使用(4条规则+6条建议)
【规则
【规则
【规则
【规则
【建议
【建议
【建议
【建议
【建议
【建议
2.程序版式(35条规则+2条建议)
2.1 空行(4条规则)
空行起着分隔程序段落的作用,空行得体将使程序的布局更加清晰。空行不会浪费内存,所以不要舍不得用空行。
【规则
【规则
【规则
【规则
// 空行 void Function1( ) { … } // 空行 void Function2( ) { … } // 空行 void Function3( ) { … } |
示例2-1(a) 函数之间的空行
// 空行 while( condition ) { statement1; // 空行 if ( condition ) { statement2; } Else { statement3; } // 空行 statement4; } |
示例2-1(b) 函数内部的空行
2.2 代码行(5条规则+1条建议)
【规则
【规则
【规则
例如:
if ( condition ) { //左括号不要另起一行 statement2; } Else { statement3; } //右括号与相应语句对齐 do { … }while(i>0); |
【规则
【规则
【建议
例如:
int width=20; /* 定义并初绐化width*/
int height=20; /* 定义并初绐化height*/
int depth=20; /* 定义并初绐化depth*/
风格良好的代码行 |
风格不良的代码行 |
int width; /* 宽度*/ int height; /* 高度*/ int depth; /* 深度*/ |
int width, height, depth; /* 宽度高度深度*/ |
x=a+b; y=c+d; z=e+f; |
x=a+b;y=c+d;z=e+f; |
if( width < height ) { dosomething(); } |
if( width < height ) dosomething(); |
for(initialization;condition;update) { dosomething(); } // 空行 other(); |
for(initialization;condition;update ) dosomething(); other(); |
2.3 代码行内的空格(6条规则+1条建议)
【规则
【规则
【规则
【规则
例如:!foo,++i,(long)getValue
【规则
【规则
例如:big.bar,pFile->bar,big[bar]
【建议
例如:for( i=0; i<10; i++ )和if( (a<=b) && (c<=d) )
风格良好的空格 |
风格不良空格 |
void Func1(int x, int y, int z); |
void Func1 (int x,int y,int z); |
if( year >= 2000 ) if( (a>=b) && (c<=d) ) |
if(year>=2000) if(a>=b&&c<=d) |
for( i=0; i<10; i++ ) |
for(i=0;i<10;i++) for (i = 0; i < 10; i ++) |
x = a < b ? a : b; |
x=a |
int *x = &y; |
int * x = & y; |
array[5] = 0; a.Function(); b->Function(); |
array [ 5 ] = 0; a.Function(); b -> Function(); |
示例2-3 代码行内的空格
2.4 对齐(4条规则)
【规则
【规则
【规则
【规则
示例: |
void Function(int x) { program code } |
if(condition) { program code } else { program code } |
for(initialization;condition;update) { program code } |
while(condition) { …program code } |
示例2-4 对齐
2.5 长行拆分(2条规则)
【规则
【规则
if( (very_longer_variable1 >= very_longer_variable12 ) && (very_longer_variable3 <= very_longer_variable14) && (very_longer_variable5 <= very_longer_variable16)) { dosomething(); } |
virtual CMatrix CMultiplyMatrix (CMatrix leftMatrix, CMatrix rightMatrix); |
for( very_long_initialization; very_long_condition; very_long_update) { dosomething(); } |
示例2-5 长行的拆分
2.6 修饰符的位置(1条规则)
【规则
例如:
char *name;
int *x, y; /* 此处y 不会被误解为指针*/
2.7 注释(12条规则)
C 语言的注释符为“/*… */”和“//”。注释通常用于:
(1)版本、版权声明;
(2)函数接口说明,包括参数类型和意义、函数类型和意义等;
(3)重要的数据类型声明、变量、算法、处理、段落等提示。
“//”为行注释。
【规则
【规则
【规则
【规则
【规则
【规则
【规则
【规则
【规则
【规则
例如:
#if 0 if( debugLevel>1 ) { ... } #endif |
【规则
【规则
3.标识符命名(15条规则+1条建议)
共性规则是被大多数程序员采纳的,我们应当在遵循这些共性规则。
命名两个基本原则:
1.含义清晰,不易混淆;
2.不与其它模块、函数的命名空间相冲突。
【规则
例如:int returnStatus;不要把currentValue 写成nowValue 。
【规则
【规则
例如Windows应用程序的标识符通常采用“大小写”混排的方式,如printStudent;而Unix应用程序的标识符通常采用“小写加下划线”的方式,如print_student。别把这两类风格混在一起用。
【规则
例如:使用get、read、fetch 、retrieve都能表达“取出”的意思,一旦软件采用哪一个则应贯穿始终。
【规则
例如:
int x, X; /* 变量x 与X 容易混淆*/
void foo(int y); /* 函数foo 与FOO 容易混淆*/
void FOO(float y);
【规则
【规则
例如: float value;float newValue;
【规则
例如:
int MinValue;
int MaxValue;
int MinValue(void);
int MaxValue(void);
【规则
例如:int recWidth;
【规则
例如:void isFull();
【规则
例如:const int MAX_LENGTH = 100;
【规则
例如:static int s_initValue; /* 静态变量*/
【规则
例如:int g_howStudent; /* 全局变量*/
【规则
例如:InputStudInfo(); //全局函数
【规则
例如:
FILE *pFile=fopen("readme.txt","rw+"); if ( pFile==NUL ) { //错误处理:打印错误信息等。 abort(); } |
可以定义成下面的包裹函数
FILE *( char const* fileName,char const *mode ) { FILE *pFile=fopen(fileName,mode); if ( pFile==NUL ) { //错误处理:打印错误信息等。 abort(); } return pFile;//正常则返回相应的文件指针 } |
以后调用的话,则可以使用下面的简洁方式:
FILE *pFile=FOPEN("readme.txt","rw++");
【建议
4.常量(7条规则)
常量是一种标识符,它的值在运行期间恒定不变。C 语言用#define 来定义常量。除了#define之外还可以用const 来定义常量。
4.1 const 与#define 的比较(2条规则)
C 语言可以用const 来定义常量,也可以用#define 来定义常量。但是前者比后者有更多的优点:
(1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换过程中可能会产生意料不到的错误。
(2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
【规则
例如:
#define MAX 100 // C 语言的宏常量
const float PI = 3.14159; // C 语言的const 常量
【规则
4.2 常量定义(5条规则)
【规则
【规则
例如:
const float RADIUS = 100;
const float DIAMETER = RADIUS * 2;
【规则
【规则
例如:
#define ERROR_DATA_LENGTH 10+1
应该这样定义:
#define ERROR_DATA_LENGTH (10+1)
这样使用malloc(5*ERROR_DATA_LENGTH)时,得到是5*(10+1)=55; 而上面的定义则得到5*10+1=51。
【规则
例如:#define WEEKS_TO_DAYS(w) (w*7)
应该写成:#define WEEKS_TO_DAYS(w) ((w)*7)
这样在翻译totalDays=WEEKS_TO_DAYS(1+2)时,才能够正确地翻译成:(1+2)*7;否则将错误地翻译成1+2*7。