C language Coding Standard
1. 声明
编码规范分为三个等级:
MUST:必须遵守
STRONGLY SUGGEST:强烈建议
SUGGEST:建议使用,但是可以自由选择使用其他的规范
2. 缩进排版
l MUST:4个空格作为缩进排版的一个单位
l STRONGLY SUGGEST:空行将逻辑相关的代码段分隔开,以提高可读性。
下列情况应该总是使用两个空行:
- 一个源文件的两个片段(section)之间
- 类声明和接口声明之间
- 两个方法之间
- 方法内的局部变量和方法的第一条语句之间
- 块注释或单行注释之前
- 一个方法内的两个逻辑段之间,用以提高可读性
l 空格
下列情况应该使用空格:
MUST:一个紧跟着括号的关键字应该被空格分开,例如:
while (true)
{
…
}
SUGGEST:空格不应该置于方法名与其左括号之间。这将有助于区分关键字和方法调用。
MUST:空白应该位于参数列表中逗号的后面
MUST:所有的二元运算符,除了“.”,应该使用空格将之与操作数分开。一元操作符和操作数之间不应加空格,比如:负号(”-”)、自增(”++”)和自减(”–”)。例如:
a += c + d;
a = (a + b) / (c * d);
while (d++ = s++)
{
n++;
}
printSize(”size is ” + foo + “\n”);
MUST:for语句中的表达式应该被空格分开,例如:
for (expr1; expr2; expr3)
SUGGEST:强制转型后应该跟一个空格,例如:
myMethod((byte) aNum, (Object) x);
myMethod((int) (cp + 5), ((int) (i + 3)) + 1);
l MUST:尽量避免一行的长度超过80个字符
因为很多终端和工具不能很好处理之。
当一个表达式无法容纳在一行内时,可以依据如下一般规则断开之:
- 在一个逗号后面断开
- 在一个操作符前面断开
- 宁可选择较高级别(higher-level)的断开,而非较低级别(lower-level)的断开
- 新的一行应该与上一行同一级别表达式的开头处对齐
- 如果以上规则导致你的代码混乱或者使你的代码都堆挤在右边,那就代之以缩进8个空格。
以下是断开方法调用的一些例子:
someMethod(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);
var = someMethod1(longExpression1,
someMethod2(longExpression2,
longExpression3));
以下是两个断开算术表达式的例子。前者更好,因为断开处位于括号表达式的外边,这是个较高级别的断开。
longName1 = longName2 * (longName3 + longName4 - longName5)
+ 4 * longname6; //PREFFER
longName1 = longName2 * (longName3 + longName4
- longName5) + 4 * longname6; //AVOID
以下是两个缩进方法声明的例子。前者是常规情形。后者若使用常规的缩进方式将会使第二行和第三行移得很靠右,所以代之以缩进8个空格
//CONVENTIONAL INDENTATION
someMethod(int anArg, Object anotherArg, String yetAnotherArg,
Object andStillAnother)
{
…
}
//INDENT 8 SPACES TO AVOID VERY DEEP INDENTS
private static synchronized horkingLongMethodName(int anArg,
Object anotherArg, String yetAnotherArg,
Object andStillAnother)
{
…
}
l STRONGLY SUGGEST:避免在if中赋值,将赋值和if判断分开。
错误的写法
if ((foo = (char *) malloc (sizeof *foo)) == 0)
{
fatal (”virtual memory exhausted”);
}
争取的写法
foo = (char *) malloc (sizeof *foo);
if (foo == 0)
{
fatal (”virtual memory exhausted”);
}
3. 注释
C++程序有两类注释:实现注释(implementation comments), 使用/*…*/和//界定的注释,和文档注释(document comments),使用docxygen工具转换成HTML文件。
实现注释用以注释代码或者实现细节。文档注释从实现自由(implementation-free)的角度描述代码的规范。它可以被那些手头没有源码的开发人员读懂。
注释应被用来给出代码的总括,并提供代码自身没有提供的附加信息。注释应该仅包含与阅读和理解程序有关的信息。例如,相应的包如何被建立或位于哪个目录下之类的信息不应包括在注释中。
在注释里,对设计决策中重要的或者不是显而易见的地方进行说明是可以的,但应避免提供代码中己清晰表达出来的重复信息。多余的的注释很容易过时。通常应避免那些代码更新就可能过时的注释。
注意:频繁的注释有时反映出代码的低质量。当你觉得被迫要加注释的时候,考虑一下重写代码使其更清晰。
注释不应写在用星号或其他字符画出来的大框里。注释不应包括诸如制表符和回退符之类的特殊字符。
l 实现注释的格式(Implementation Comment Formats)
程序可以有4种实现注释的风格:块(block)、单行(single-line)、尾端(trailing)和行末(end-of-line)。
采用Doxygen QT注释方法,以便于生成文档
/*!
* … 程序注释…
*/
如果不想生成文档,则使用下面块注释方法:
/*
* … 程序注释…
*/
Doxygen标签:
@file 档案的批注说明
@author 作者的信息
@brief 用于class或function的批注中,后边为class或function的批注说明
@param 格式为: @param arg name 主要用于函式说明中,后边接参数的名字,然后再接关于参数的说明
@return 接函数返回值的说明,用于function的批注中
@retval 格式为:@retval value 传回值说明 主要用于函式说明中,说明特定传回值的意义。所以后面要先接一个传回值。然后在放该传回值的说明。
例子:
/*!
* @file xmlparse.c
* @author 作者的信息
* @brief 解析XML文件
*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
char array[10]; // array
int index ; // index of the array
index = 0;
printf(”Hello world! %d\n”, index);
return 0;
}
/*!
* @author summer
* @brief test world function
* @param int index : index of array.
* @param const char * name : name of the file
* @return test result
* @retval int : 0 is ok, -1 is error
*/
int test(int index, const char * name)
{
printf(”test world.\n”);
return 0;
}
l 单行注释(Single-Line Comments)
短注释可以显示在一行内,并与其后的代码具有一样的缩进层级。如果一个注释不能在一行内写完,就该采用块注释(参见“块注释“)。单行注释之前应该有一个空行。以下是一个Java代码中单行注释的例子:
if (condition) {
/* Handle the condition. */
…
}
l 尾端注释(Trailing Comments)
极短的注释可以与它们所要描述的代码位于同一行,但是应该有足够的空白来分开代码和注释。若有多个短注释出现于大段代码中,它们应该具有相同的缩进。
以下是一个Java代码中尾端注释的例子:
if (a == 2) {
return TRUE; /* special case */
} else {
return isPrime(a); /* works only for odd a */
}
注释界定符“//”,可以注释掉整行或者一行中的一部分。它一般不用于连续多行的注释文本;
if (foo > 1)
{
// Do a double-flip.
…
}
else {
return false; // Explain why here.
}
l 开头注释(Beginning Comments)
MUST:所有的源文件都应该在开头有一个C语言风格的注释,其中列出类名、版本信息、日期和版权声明:
/*
* description
*
* Date
*
* Copyright notice
*/
l STRONGLY SUGGEST:在函数前面注释其用途,说明参数的范围,特值。
l SUGGEST:static局部变量要有注释,全局变量要有注释。
l SUGGEST:#if … #endif 要有注释,除非特简单的。注释要描述结束条件。例:
#ifdef foo
…
#else /* not foo */
…
#endif /* not foo */
#ifdef foo
…
#endif /* foo */
#ifndef foo
…
#else /* foo */
…
#endif /* foo */
#ifndef foo
…
#endif /* not foo */
l STRONGLY SUGGEST:尽量使用英文注释。
4. 声明
l STRONGLY SUGGEST:推荐一行一个声明,因为这样以利于写注释。亦即
int level; // indentation level
int size; // size of table
要优于,
int level, size;
不要将不同类型变量的声明放在同一行,例如:
int foo, fooarray[]; //WRONG!
注意:上面的例子中,在类型和标识符之间放了一个空格,另一种被允许的替代方式是使用制表符:
int level; // indentation level
int size; // size of table
Object currentEntry; // currently selected table entry
l STRONGLY SUGGEST:尽量在声明局部变量的同时初始化。唯一不这么做的理由是变量的初始值依赖于某些先前发生的计算。
l STRONGLY SUGGEST:只在代码块的开始处声明变量。(一个块是指任何被包含在大括号“{”和“}”中间的代码。)不要在首次用到该变量时才声明之。这会把注意力不集中的程序员搞糊涂,同时会妨碍代码在该作用域内的可移植性。
void myMethod()
{
int int1 = 0; // beginning of method block
if (condition) {
int int2 = 0; // beginning of “if” block
…
}
}
该规则的一个例外是for循环的索引变量
for (int i = 0; i < maxLoops; i++) { … }
MUST:避免声明的局部变量覆盖上一级声明的变量。例如,不要在内部代码块中声明相同的变量名:
int count;
…
myMethod()
{
if (condition)
{
int count = 0; // AVOID!
…
}
…
}
l STRONGLY SUGGEST:避免在函数内部使用temp这样的变量存储各种各样的数据,尽量使用有意义的名字。
l MUST:不要使用和全局变量同名的局部变量。
5. 语句
l 简单语句
MUST:每行至多包含一条语句,例如:
argv++; // Correct
argc–; // Correct
argv++; argc–; // AVOID!
l 复合语句
复合语句是包含在大括号中的语句序列,形如“{ 语句 }”。例如下面各段。
MUST:被括其中的语句应该较之复合语句缩进一个层次
STRONGLY SUGGEST:左大括号“{”应另起一行,并与复合语句首行对齐;右大括号“}”应另起一行并与复合语句首行对齐。
STRONGLY SUGGEST:大括号可以被用于所有语句,包括单个语句,只要这些语句是诸如if-else或for控制结构的一部分。这样便于添加语句而无需担心由于忘了加括号而引入bug。
l 返回语句
STRONGLY SUGGEST:一个带返回值的return语句不使用小括号“()”,除非它们以某种方式使返回值更为显见。例如:
return;
return myDisk.size();
return (size ? size : defaultSize);
l if,if-else,if else-if else语句(if, if-else, if else-if else Statements)
STRONGLY SUGGEST:if-else语句应该具有如下格式:
if (condition)
{
statements;
}
if (condition)
{
statements;
}
else
{
statements;
}
if (condition)
{
statements;
}
else if (condition)
{
statements;
}
else
{
statements;
}
注意:if语句总是用“{”和“}”括起来,避免使用如下容易引起错误的格式:
if (condition) //AVOID! THIS OMITS THE BRACES {}!
statement;
l for语句
STRONGLY SUGGEST:一个for语句应该具有如下格式:
for (initialization; condition; update)
{
statements;
}
STRONGLY SUGGEST:一个空的for语句(所有工作都在初始化,条件判断,更新子句中完成)应该具有如下格式:
for (initialization; condition; update);
当在for语句的初始化或更新子句中使用逗号时,避免因使用三个以上变量,而导致复杂度提高。若需要,可以在for循环之前(为初始化子句)或for循环末尾(为更新子句)使用单独的语句。
l while语句
STRONGLY SUGGEST:一个while语句应该具有如下格式
while (condition)
{
statements;
}
一个空的while语句应该具有如下格式:
while (condition);
l do-while语句
STRONGLY SUGGEST:一个do-while语句应该具有如下格式:
do
{
statements;
} while (condition);
l switch语句
STRONGLY SUGGEST:一个switch语句应该具有如下格式:
switch (condition)
{
case ABC:
statements;
/* falls through */
case DEF:
statements;
break;
case XYZ:
statements;
break;
default:
statements;
break;
}
每当一个case顺着往下执行时(因为没有break语句),通常应在break语句的位置添加注释。上面的示例代码中就包含注释/* falls through */。
l try-catch语句
STRONGLY SUGGEST:一个try-catch语句应该具有如下格式:
try
{
statements;
} catch (ExceptionClass e)
{
statements;
}
一个try-catch语句后面也可能跟着一个finally语句,不论try代码块是否顺利执行完,它都会被执行。
try
{
statements;
} catch (ExceptionClass e)
{
statements;
}
finally
{
statements;
}
健壮性
l STRONGLY SUGGEST:不要对数据结构作随意的限制,比如文件名长度,文件数,尽量动态分配。
l MUST:检查每个系统调用的返回值。并且记录perror的输出、产生错误的文件名和程序名。
l MUST:检查malloc和realloc的返回值是否为0。
l MUST:新写的程序用-Wall编译,如果是继承过来的程序,用-Wall编译产生成堆的Warning,可以不用-Wall编译。
6. 命名规范
SUGGEST:命名规范使程序更易读,从而更易于理解。它们也可以提供一些有关标识符功能的信息,以助于理解代码,例如,不论它是一个常量,包,还是类。
|
标识符类型 |
命名规则 |
例子 |
|
类(Classes) |
命名规则:类名是个一名词,采用大小写混合的方式,每个单词的首字母大写。尽量使你的类名简洁而富于描述。使用完整单词,避免缩写词(除非该缩写词被更广泛使用,像URL,HTML) |
class Raster; |
|
方法(Methods) |
方法名是一个动词,采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。 或者所有都小写,中间用”_”隔开; 或者所有单词第一个字母大写; 但同一个项目中,应保持同一种风格(除调用的类库的方法外) |
run(); get_next_node_name(); GetNextNodeName (); |
|
变量(Variables) |
除了变量名外,所有实例,包括类,类常量,均采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。变量名不应以下划线或美元符号开头,尽管这在语法上是允许的。 对全局变量,可以前面加前缀”g_”; |
char c; |
|
实例变量(Instance Variables) |
大小写规则和变量名相似,除了前面需要一个下划线 |
int _employeeId; |
|
常量(Constants) |
类常量和ANSI常量的声明,应该全部大写,单词间用下划线隔开。(尽量避免ANSI常量,容易引起错误) |
static int MIN_WIDTH = 4; |
7. 编写Library
l STRONGLY SUGGEST:尽量使库函数“可重入”
l MUST:给每个库选择一个至少两个字符的前缀,所有对外公开的函数和变量都用这个前缀开始。
l STRONGLY SUGGEST:未公开的entry point以“_”字符开始。
最新评论