0. 错误处理
- 错误应该在什么地方报出来?在错误栈的最底层,还是层层打印?
- 错误何时输出到日志,何时显示给用户?
- 错误处理的对策是退出,重试,还是尝试替代方案?
1. 魔数
由于魔术的可读性很差,所以一般不允许使用魔术。
有些情况下可以使用魔术,关键还是要看可读性。
注:字符串字面量可以直接使用,除非是多次出现,可能会修改。
2. 函数规范
- 单个函数行数不超过
50
行 - 参数个数不超过
5
个 - 不在参数里面直接使用布尔值,应该换成枚举值。(为了可读性)
- 单行不超过
80
个字符,应该考虑折行 - 函数参数不能使用指定长度的数组
char argv[5]
,因为会退化为指针,实际上sizeof(argv) == sizeof(char*)
- 命名风格:
<type> + <do> + <sth>
,例如:fopen
- 参数排列的顺序:
<typename> <out> <out/in> <in> <opt>
3. 不使用复杂的 else if
语句
第一种情况:else if
和 if
针对的目标不同:
if (A > 0) ...
else if (B >0) ...
else ...
// 可以改为:
if (A > 0) ...
else {
if (B > 0) ...
else ...
}
第二种情况:else if
有多个条件,且针对不同的目标:
if (A > 0) ...
else if (A != 0 || B == 0) ...
else ....
4. 异常处理
参数检查:
- 对于内部函数,应该使用
assert
检查每一个参数 - 对于外部函数,应该使用
if
检查参数,并且进行错误处理(返回值,抛出异常等)
注:对外提供的函数,不要打印控制台信息,会造成污染。
使用外部数据:进程间通信,IO得到的数据,应该使用 if
进行检查
检查返回值:需要使用 if
检查,并且进行错误处理。
如果确认不会出错,或者不需要处理错误,可以通过 (void)
来显式地忽略。
5. 变量初始化
变量在使用前应当初始化,为了防止程序员引发的BUG。
指针在使用前应当初始化:
some_t *ptr = NULL;
内存在分配后应当初始化:
// 数组初始化:
int arr[SIZE] = { 0 };
// 字符串初始化:
char str[SIZE] = "\0";
// 内存块初始化:
memset(...);
6. 资源释放
资源在释放后应该置为无效值:
free(ptr);
ptr = 0;
除非这个资源不会再使用了,例如:局部变量,程序返回时等
7. 不混用文件机制
存在这几种文件机制:
- C语言:
printf, fprintf, fseek, fgets
POSIX
:open, lseek
C++
的stream
:ostream, istream, fstream
不要在一段代码中同时使用这几种机制,因为他们各自有自己的缓冲区