C++ RuleChecker Rules
有关 C++的 89 个规则,其中有 35 个规则允许根据实际情况配置如何使用(方法是调整
规则提供的参数),其余 54 个规则不允许配置(理由是:业界认可的通行规则或者专家规则)。
这 89 个规则,实际使用中,可以选择其任意子集。
其中,前 70 条规则,是从多家公司收集的编程规则集,提取的精华。后 19 条规则,是
Scott Meyers 规则。
1)
ansi(Function Declarations in ANSI Syntax)
描述:函数的声明和实现必须符合 ANSI 语法。
用意:提高代码的易读性和可移植性。
配置 1:name
函数的所有参数必须命名,并且必须在函数声明中说明各个参数的类型。
配置 2:void
禁止函数的参数为空。
例子:
正确写法
f(int a, char *b);
f(int a, char *b)
{ ...}
f(void);
错误写法
f(int, char*);
f(a, b)
int a;
char *b
{ ...}
f();
asscal (don’t use Assignment inside Function Calls)
2)
描述:不允许在函数调用中使用赋值运算符(=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=,
^=,++,--)。
用意:去除有关赋值顺序的不明确性。
配置:无。
例子:
正确写法
n=f(b);
b++;
错误写法
n=f(b++);
3)
asscon (don’t use Assignment inside conditions)
描述:不允许在 if , while , for , switch 控制指令中的条件表达式中使用赋值运算符(=, +=,
-=, *=, /=, %=, >>=, <<=, &=, |=, ^=,++,--)。
用意:这个语句 if(x=y) 是不清楚不明确的,也许有人认为作者想写成 if (x= =y)。
配置:无
例子:
正确写法
x -= dx;
第 1 页 共 20 页
错误写法
if (x -= dx) { ...
if (x) { ...
for (i=j=n; i > 0; i--, j--){ ... for (i=j=n; i-- > 0; j--) {..
4)
assexp ( don’t nest assignments inside expressions)
描述:在表达式内部
一个运算数只能被赋值一次。
如果有多个赋值运算符,一个被赋值的运算数能且只能出现在它被赋值的位
置。
用意:去除有关赋值顺序的不明确性
配置:无
例子:
正确写法
错误写法
i = t[i++];
a=b=c+a;
i=t[i]=15;
5)
blockdecl (place Declarations at the beginning of blocks)
描述:声明必须在语句体的开始处。
用意:代码易读性。
配置:无
例子:
正确写法
错误写法
6) Boolean (don’t use abbreviated Boolean expression)
描述:不允许使用缩写的布尔表达式。
用意:代码易读性
配置:无
例子:
正确写法
AlwaysTrue = true;
while (AlwaysTrue == true) {
if (test == true) {
for (i=1; function_call(i); i++){
错误写法
while (1) {
if (test) {
for (i=1; function_call(i); i++) {
7)
brkcont (Break and Continue forbidden, except in switch statements)
描述:break 和 continue 指令禁止使用在控制语句(for, do ,while)的条件表达式中。然
而,break 指令被允许使用在 switch 语句的结构体中。
用意:像 goto 一样,这些指令会改变代码的结构。在循环中禁止使用它们将使代码比较
容易理解。
第 2 页 共 20 页
配置:无
例子:
正确写法
错误写法
8)
classuese (don’t use methods not known in the user class)
描述:下列表达式都是不允许的:u.v.a, u.v.f(),u.g().a, u.g().f(),表达式
中使用->操作符也是一样。
用意:阻止通过串联(连续的)的调用方法,调用一个在用户类中不知道的类方法(隐
式使用)。
配置:无
例子:
正确写法
错误写法
myWindow.itsButton.push();
Error->pos.line;
9)
cmclass (use a single class per code file)
描述:一个代码文件中,每个函数都必须属于一个相同的类。
C 函数被认为属于 main 类。
默认情况下,一个代码文件有一个如下的后缀:*.cc, *.cxx, *.cpp,*.C or *.c。
用意:代码易读性。
配置:使用一个字符串来表示那些需要考虑的代码文件的类型。
例子:
正确写法
错误写法
10) cmdef (code files should not contain class declarations)
描述:代码文件不能包含任何类的声明。
C 函数被认为属于 main 类。
默认情况下,一个代码文件有一个如下的后缀:*.cc, *.cxx, *.cpp,*.C or *.c。
用意:代码易读性。
配置:使用一个字符串来表示那些需要考虑的代码文件的类型。
例子:
正确写法
错误写法
11) condop (the ternary operator (? : ) should not be used)
描述:三重条件操作符? ... : ...禁止使用。
用意:代码易读性。
配置:无
例子:
第 3 页 共 20 页
正确写法
错误写法
12) const (literal constants should not be used)
描述:数字和字符串必须被作为常量声明,而不是被直接作为文字形式在程序中使用。
可以指定允许使用的文字常量。默认情况下允许直接使用"", " ", "0" and "1"。
用意:代码易维护性。
配置:一个字符串列表用来表示允许直接使用的常量。
例子:
正确写法
#define TAB_SIZE 100
enum i_val { ok =7; ko =11};
const char HelloWorld[] = "Hello
World.\n";
char tab[TAB_SIZE];
i_val i;
...
if (i == ok) {
p = HelloWorld;}
错误写法
char tab[100];
int i;
...
if (i == 7) {
p = "Hello World.\n";}
13) constrcpy (Each class must contain an explicit copy constructor)
描述:每个类都必须明确包含它的拷贝构造函数。
用意:确保作者已经考虑到拷贝该类的对象的方法。
配置:如果使用了字符串“dynalloc”,表示这个规则只有在类的成员中包含指针的时候
才检查。
例子:
错误写法
正确写法
class aClass {
...
aClass(const aClass &object); //
"const" is optional
...
};
14) constrdef (Each class must contain an explicit default constructor)
描述:每个类都必须明确包含它的默认构造函数。
用意:确保作者已经考虑到初始化该类的方法。
配置: 无
例子:
错误写法
正确写法
class aClass {
...
aClass();
...
第 4 页 共 20 页
};
15) ctrlblock (Block statements should always be used in control structures)
描述: 在控制语句段(if , for , while , do)中必须使用{}
用意:消除结构范围的不清楚性以及使代码易读易改。
配置: 无
例子:
正确写法
if (x == 0) {
return;
} else {
while (x > min) {
x--;
}
}
错误写法
if (x == 0) return;
else
while (x > min)
x--;
16) delarray (Use square brackets when deleting arrays to ensure full array is deallocated)
描述: 当删除数组时必须使用[]。
用意:确保恰当的内存被释放。
配置: 无
例子:
正确写法
int *table = new int[7];
delete [] table;
错误写法
int *table = new int[7];
delete table;
delete [10] table;
局限 1:该规则,在一些复杂的情况下失效(不起作用)
例子 1::
int ** myarray = new int[2];
myarray[0] = new int[10];
delete myarray; // 违反规则
delete myarray[0]; // 不违反规则
例子 2:
class A
{
public:
int *tab;
...
};
A var;
var.tab = new int[10];
delete var.tab; //不违反规则
第 5 页 共 20 页
局限 2:当 new 操作被隐式使用,则规则不起作用
int * create_array(int nb)
{
return (new int[nb]);
}
...
int * myarray = create_array(10);
delete myarray; // 不违反规则
17) destr(Each class must contain an explicit destructor)
描述:每个类都必须明确包含它的析构函数。
用意:确保作者已经考虑到销毁该类的实例的方法。
配置: 无
例子:
错误写法
正确写法
class aClass {
...
~aClass(aClass &object);
...
};
18) dmaccess (access to a class’ data members should be restricted)
描述: 类的接口必须是纯粹的函数:数据成员的定义被限制。
用意:访问一个对象状态的好的方法是通过它的方法,而不是对象的数据成员。类的数
据成员应当是 private 或者至少是 protected。
配置: 一个字符串的列表对应于禁止访问的数据成员。
例子:
正确写法
错误写法
19) exprcplx (syntactic tree complexity must be limited)
描述: 表达式的复杂度必须小于一个给定的值。复杂度的计算与语法树以及它的节点
个数有关。默认情况下,最大的审核值复杂级为 13。
用意:代码易读性。
配置: 一个数用来表示最大的审核值复杂级
例子:
(b+c*d) + (b*f(c)*d)
有 8 个操作符和 7 个操作数.,语法树有 16 个节点,复杂度为 16。
20) exprparenth(Parenthesses should be used to indicate evaluation order)
描述: 在表达式中,每个二元的和三元的操作符必须放在()中。
第 6 页 共 20 页
如果使用参数 partpar,则:
当右边的操作符与当前操作符同是+或者*则,禁止为右边的操作数使用();
同上,赋值操作符右边的操作数禁止使用();
禁止在表达式的第一级使用();
用意:减少运算顺序的不明确性。
配置:参数 partpar
例子:
// do not write
result = fact / 100 + rem;
// write
result = ((fact / 100) + rem);
// or write, with the partpar option
result = (fact / 100) + rem;
// with the partpar option, write
result = (fact * ind * 100) + rem + 10 + (coeff ** c);
// instead of
result = ((fact * (ind * 100)) + (rem + (10 + (coeff ** c))));
21)
fntype(Function type must always be declared)
描述: 每个函数必须声明它的类型。如果不返回任何值,它必须被声明为 void 类型。
用意:提高代码的可移植性。
22)
forinit (Loop counters must be initialized within the loop)
描述: 循环的计数器(在 for 循环中)必须在循环的初始化语句段中初始化。由循环头
中的第三个元素来判断哪个是循环计数器。
用意:通过这种要求,循环计数器被确保初始化,循环易于理解和控制。
例子:
正确写法
for (int i = 0; i < 10; i++) ... for (int i; i < 10; i++) ...
错误写法
for (int j = 0; j < 10; i++) ...
for (int j = 10; i < j; i++) ...
for (int j = 1; i < funct(j);
i+=j) ...
23)
frnclass(Friend classes must be declared at he beginning of th class)
描述: 如果使用友员类,则友员类必须在类的开始处被声明(在类的成员被声明之前)。
24)
funcptr(Do not use function pointers)
描述: 不使用函数指针。
例子 1:
void print(int i)
第 7 页 共 20 页
{ std::cout << i << std::endl; }
void (*func_1)(int);
func_1 = &print;
func_1( 1);
(*func_1)( 1);
例子 2:
typedef void (*PFUNC)(int);
PFUNC pfunc;
25)
funcree(Prohibit specified function names)
描述:特定的名字不能用来声明或者定义函数,也不能调用。默认情况下,不禁止任何
函数名。
用意:禁止使用一些比较危险的系统函数。
配置:一个字符串列表用来表示需要禁止使用的函数名。
例子:
// 如果禁止使用 system 函数
//下面的使用违反规则
int system(char *command);
int system(char *command)
{
...
}
system("cp file /tmp");
26) globinit (Global variable must be initialized when they are defined)
描述: 全局变量必须在定义的时候初始化。
用意:不是所有的编译器都给予相同的默认值。可以通过控制变量的值来避免一些不期
望的动作。当声明全局变量的时候就赋初值可以确保在使用它们之前初始化。
27) goto(Prohibit the use of the goto statement)
描述: goto 语句不能使用。
也可以配置某些特定的标签(label)可以使用 goto
用意:确保遵守结构化的编程规则,代码易于理解。
配置:可以使用 goto 的 label 列表
28) Headercom(Modules must be preceded by a structured comment)
描述: 模块必须有一个头注释。头注释的格式依赖于在 meitric 类型中定义的模块类型。
默认情况下,头注释如下:
///////////////////////////////////////////
/////
// Name: program
// Author: Andrieu
// Date: 08/07/96
第 8 页 共 20 页