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 ifif 针对的目标不同:

  1. if (A > 0) ...
  2. else if (B >0) ...
  3. else ...
  4. // 可以改为:
  5. if (A > 0) ...
  6. else {
  7. if (B > 0) ...
  8. else ...
  9. }

第二种情况:else if 有多个条件,且针对不同的目标:

  1. if (A > 0) ...
  2. else if (A != 0 || B == 0) ...
  3. else ....

4. 异常处理

参数检查:

  • 对于内部函数,应该使用 assert 检查每一个参数
  • 对于外部函数,应该使用 if 检查参数,并且进行错误处理(返回值,抛出异常等)

注:对外提供的函数,不要打印控制台信息,会造成污染。

使用外部数据:进程间通信,IO得到的数据,应该使用 if 进行检查

检查返回值:需要使用 if 检查,并且进行错误处理。

如果确认不会出错,或者不需要处理错误,可以通过 (void) 来显式地忽略。

5. 变量初始化

变量在使用前应当初始化,为了防止程序员引发的BUG。

指针在使用前应当初始化:

  1. some_t *ptr = NULL;

内存在分配后应当初始化:

  1. // 数组初始化:
  2. int arr[SIZE] = { 0 };
  3. // 字符串初始化:
  4. char str[SIZE] = "\0";
  5. // 内存块初始化:
  6. memset(...);

6. 资源释放

资源在释放后应该置为无效值:

  1. free(ptr);
  2. ptr = 0;

除非这个资源不会再使用了,例如:局部变量,程序返回时等

7. 不混用文件机制

存在这几种文件机制:

  • C语言:printf, fprintf, fseek, fgets
  • POSIXopen, lseek
  • C++streamostream, istream, fstream

不要在一段代码中同时使用这几种机制,因为他们各自有自己的缓冲区