Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1440617
  • 博文数量: 463
  • 博客积分: 10540
  • 博客等级: 上将
  • 技术积分: 5450
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-12 08:30
文章分类

全部博文(463)

文章存档

2014年(2)

2012年(14)

2011年(42)

2010年(18)

2009年(78)

2008年(35)

2007年(182)

2006年(92)

我的朋友

分类: 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.0.1

* 作者:修改者名字,修改日期:200545

* 修改的地方描述:

*/

/*

* 取代版本:1.0.0

* 原作者:原作者名字,完成日期:20041231

*/

示例1-1 版权和版本的声明

版本标识:采用<主版本号>.<次版本号>.<修订号> 来命名自己产品的编号。一般这样约定,如果次版本号是偶数(如024等),代表正式版本,如果次版本号是奇数(135),代表开发过程中的测试版本。修订号则相当于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-2 C头文件结构

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-3 C定义文件的结构

1.4头文件和定义文件使用(4条规则+6条建议)

【规则1-2-1】在复杂的工程文件中,为了防止头文件被重复引用,应使用ifndef/define/endif 结构产生预处理块。

【规则1-2-2】用#include 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。

【规则1-2-3】用#include “filename.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。

【规则1-2-4】只引用必需的头文件,不要为了防止忘记包含头文件而在每个文件开始添加很多的头文件。

【建议1-2-1】不要在头文件中定义常量或变量,注意头文件只是用来声明。

【建议1-2-2】不提倡使用全局变量,尽量不要在头文件中出现像“extern int width这类声明。

【建议1-2-3】将非系统的函数库放在一个单独的目录下引用。

【建议1-2-4】头文件应按功能组织在一起,即对单独子系统的声明应放在单独的头文件中。此外,当代码从一个平台移植到另一个平台时有可能发生更改的声明应位于单独的头文件中,并进行相应的注释。

【建议1-2-5】避免使用与函数库中专用头文件名相同的头文件名。语句 #include "math.h" 如果在当前目录中找不到所期望文件的话,会包括标准库 math 头文件。

【建议1-2-6】包含头文件时一般不使用绝对路径名。

2.程序版式(35条规则+2条建议)

2.1 空行(4条规则)

空行起着分隔程序段落的作用,空行得体将使程序的布局更加清晰。空行不会浪费内存,所以不要舍不得用空行。

【规则2-1-1】在函数内部局部变量定义结束之后处理语句之前要加空行。

【规则2-1-2】在每个函数定义结束之后都要加空行。参见示例2-1a)。

【规则2-1-3】函数返回语句和其他语句之间使用空行分开。

【规则2-1-4】在一个函数体内,逻辑上密切相关的语句之间不加空行,其它地方应加空行分隔。参见示例2-1b)。

 

// 空行

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条建议)

【规则2-2-1】一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便写注释。

【规则2-2-2ifforwhiledo 等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加{}表明是一个语句块。

【规则2-2-3】左花括号与语句同行(不要另起一行),右花括号要单独占一行。但是在do-whilestructunion及其后有的除外,要同在一行。

例如:

if ( condition ) {  //左括号不要另起一行

statement2;

}

Else { 

statement3;

}     //右括号与相应语句对齐

 

 

do

{

}while(i>0);

 

【规则2-2-4switch语句中的每个case语句各占一行,当某个case语句不需要break语句最好加注释声明。

【规则2-2-5】并列的语句行应该按照字母顺序排序,如变量定义和switch中的case语句等。

【建议2-2-1】尽可能在定义变量的同时初始化该变量(就近原则),如果变量的引用处和其定义处相隔较远,变量的初始化很容易被忘记。如果引用了未被初始化的变量,可能会导致程序错误。本建议可以减少隐患。

例如:

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条建议)

【规则2-3-1】关键字之后要留空格。象constcase 等关键字之后至少要留一个空格,否则无法辨析关键字。象ifforwhile 等关键字和紧跟的左括号之后应留一个空格,右括号前也对应要留一个空格,以突出关键字。例如:if( a==b )

【规则2-3-2】函数名之后不要留空格,紧跟左括号,以与关键字区别。例如:void calcvoid;

【规则2-3-3之后要留空格,如Function(x, y, z)。如果‘;’不是一行的结束符号,其后要留空格,如for( initialization; condition; update )

【规则2-3-4】不要在单目运算符(“!”“~”“++”“--”“&”)和其操作对象间加空格。

 例如:!foo,++i,(long)getValue

【规则2-3-5】赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”“+=”“>=”“<=”“+”“*”“%”“&&”“||”“<<”,“^”等二元操作符的前后应当加空格。

【规则2-3-6】象[]“.”“->”这类操作符前后不加空格。

 例如:big.bar,pFile->bar,big[bar]

【建议2-3-1】对于表达式较长的for语句和if语句,为了紧凑起见可以适当地去掉一些空格.

例如: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条规则)

【规则2-4-1】程序的分界符‘}’应独占一行并且位于同一列,同时与引用它的语句左对齐,分界符‘{’不用独占一行紧跟在语句后。

【规则2-4-2】水平缩进每次使用四个空格即可(定义一个tab键为四个空格)

【规则2-4-3】同属于一个语句块的代码对齐。

【规则2-4-4{ }之内的代码块在一个tab键处左对齐。

示例:

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条规则)

【规则2-5-1】代码行最大长度宜控制在7080个字符以内。代码行不宜过长,否则不便于阅读,也不便于打印。

【规则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条规则)

【规则2-6-1】将修饰符 * 和 &紧靠变量名,以免引起误解。

例如:

char *name;

int *x, y;   /* 此处y 不会被误解为指针*/

2.7 注释(12条规则)

C 语言的注释符为“/*… */”“//”。注释通常用于:

1)版本、版权声明;

2)函数接口说明,包括参数类型和意义、函数类型和意义等;

3)重要的数据类型声明、变量、算法、处理、段落等提示。

“//”为行注释。

【规则2-7-1】注释是对代码作用的提示,而不是文档。注释的频度要合适,一般要求占程序总行数的1/51/4

【规则2-7-2】边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。

【规则2-7-3】注释应准确、易懂,防止注释有二义性。错误的注释不但无益反而有害。

【规则2-7-4】尽量避免在注释中使用缩写,特别是不常用的缩写。根据维护程序的对象确定使用中文还是使用英文。

【规则2-7-5】注释的位置应与被描述代码相邻,可以放在代码的上方或右方,一般不宜放在下方。

【规则2-7-6】当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。

【规则2-7-7】尽量不要在语句指令中添加注释。

【规则2-7-8】注释不具备约束使用者行为的能力。

【规则2-7-9】给一行代码添加注释最好使用“//”,比较清楚。

【规则2-7-10】不要使用/**/注释掉大量代码,而要使用#if0条件编译语句

例如:

#if 0

if( debugLevel>1 ) {

...

}

#endif

【规则2-7-11】行末注释最好对齐。

【规则2-7-12】应对包含的头文件进行行末注释。

3.标识符命名(15条规则+1条建议)

共性规则是被大多数程序员采纳的,我们应当在遵循这些共性规则。

命名两个基本原则:

1.含义清晰,不易混淆;

2.不与其它模块、函数的命名空间相冲突。

【规则3-1-1】标识符要清楚、准确、简单而且尽量可发音的英文名字

例如:int returnStatus;不要把currentValue 写成nowValue

【规则3-1-2】标识符的长度应当符合“min-length && max-information”(最短并包含信息最多)原则。单字符的名字也是有用的,常见的如ijkmnxyz 等,它们通常可用作函数内的局部变量。

【规则3-1-3】命名规则尽量与所采用的操作系统或开发工具的风格保持一致。

例如Windows应用程序的标识符通常采用大小写混排的方式,如printStudent;而Unix应用程序的标识符通常采用小写加下划线的方式,如print_student。别把这两类风格混在一起用。

【规则3-1-4】尽量选择通用词汇并保持整个软件风格一致。

例如:使用getreadfetch retrieve都能表达取出的意思,一旦软件采用哪一个则应贯穿始终。

【规则3-1-5】程序中不要出现仅靠大小写区分的相似的标识符。

例如:

int x, X;       /* 变量x X 容易混淆*/

void foo(int y);   /* 函数foo FOO 容易混淆*/

void FOO(float y);

【规则3-1-6】程序中不要出现标识符完全相同的局部变量和全局变量,尽管可能两者的作用域不同而不会发生语法错误,但会使人误解。

【规则3-1-7】变量的名字应当使用名词或者形容词+名词

例如: float value;float newValue;

【规则3-1-8】用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

例如:

int MinValue;

int MaxValue;

int MinValue(void);

int MaxValue(void);

【规则3-1-9】变量和参数首字母小写,其后每个英文单词的第一个字母大写,其它小写。

例如:int recWidth;

【规则3-1-10】标识布尔型的变量或函数名称一般使用is作为前缀。

例如:void isFull()

【规则3-1-11】常量全用大写字母,用下划线分割单词。

例如:const int MAX_LENGTH = 100;

【规则3-1-12】静态变量加前缀s_(表示static)。

例如:static int s_initValue; /* 静态变量*/

【规则3-1-13】如果需要定义全局变量,则变量加前缀g_(表示global)。

例如:int g_howStudent; /* 全局变量*/

【规则3-1-14】函数名用大写字母开头的单词组合而成。由多个单词组成的标识符每个单词首字母大写。其它小写。

例如:InputStudInfo(); //全局函数

【规则3-1-15】一般错误包裹函数名全部大写。

例如:

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++");

【建议3-1-1】尽量避免名字中出现数字编号,如value1value2 等,除非逻辑上的确需要编号。

4.常量(7条规则)

常量是一种标识符,它的值在运行期间恒定不变。C 语言用#define 来定义常量。除了#define之外还可以用const 来定义常量。

4.1 const #define 的比较(2条规则)

C 语言可以用const 来定义常量,也可以用#define 来定义常量。但是前者比后者有更多的优点:

1 const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换过程中可能会产生意料不到的错误。

2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。

【规则4-1-1】尽量使用含义直观的常量来表示那些将在程序中多次出现的数字或字符串。

例如:

#define MAX 100     // C 语言的宏常量

const float PI = 3.14159; // C 语言的const 常量

【规则4-1-2】尽量使用const定义常量替代宏定义常量。

4.2 常量定义(5条规则)

【规则4-2-1】需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义文件的头部。为便于管理,可以把不同模块的常量集中存放在一个公共的头文件中。

【规则4-2-2】如果某一常量与其它常量密切相关,则应在定义中包含这种关系,而不应给出一些孤立的值。

例如:

const float RADIUS = 100;

const float DIAMETER = RADIUS * 2;

【规则4-2-3enum中的枚举常量应以大写字母开头或全部大写。

【规则4-2-4】如果宏值多于一项,一定使用括号。

例如:

#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

【规则4-2-5】函数宏的每个参数都要括起来。

例如:#define WEEKS_TO_DAYS(w) (w*7)

应该写成:#define WEEKS_TO_DAYS(w) ((w)*7)

这样在翻译totalDaysWEEKS_TO_DAYS(1+2)时,才能够正确地翻译成:(1+2)*7;否则将错误地翻译成1+2*7

阅读(824) | 评论(0) | 转发(0) |
0

上一篇:CVS完全手册

下一篇:C语言编码规范[2]

给主人留下些什么吧!~~