总的来说,评价代码好坏的标准万变不离其宗,主要包括如下几个方面:
稳定性:在不同的负载和应用场景下,都能得到正确的输出,性能也没比较大的抖动
健壮性:考虑到各种corner
cases
鲁棒性:错误的输入、配置、异常或故障不会扩散到其他(更多)的模块
可扩展性:上下层模块之间有固定的接口,横向模块之间低耦合
易维护程度:可读性强,准确且足够的注释,便于调试,容易测试和调试
根据最近的编程心得,个人认为可有从下面的两个方面进行考虑:
1、明确需求和接口,选好算法和数据结构
开始编程之前,可用需求定义、层次划分、模块设计、接口定义先行,不需要快速实现C代码,可以先分层、划分好子模块,确定好具体的算法和架构后,先大致定义出头文件,并且在头文件中用注释的方式快速描述、确认头文件中各个接口函数的输入、输出参数,以及前提假设、临界条件。
2.利用已有的编码经验教训,使用静态和动态工具检查
下面列出了许多常用的C 编码规范,可供参考和检查:
- 头文件中 #ifndef
XXX; #define XXX;#endif 用来防止重复应用; - 考虑进对 C++的支持;extern
"C" - 使用严格定义的数据类型:用uint8_t;
uint32_t, uint64_t,size_t等代替char/int/short/long - 用indent 统一格式;
- 编译时打开所有警告:
-Wall - 用splint做安全和稳定性检查;
- 封装容易出现问题的alloc();free();ralloc();realloc()
- 甄别错误和异常情况,在调试版代码中使用 assert(),
assert_perror(),并且保证在正式release中去掉。 - 调试版本总考虑用不同的代码/算法确保核心代码;
- 测试代码和功能代码并行进行,并且尽快搭建针对所开发模块的自动测试框架;
- 利用GDB进行代码走读
对走读过程中碰到的&&
/||/ ? :操作符号,可先打印出当前的状态,然后可以通过gdb来确认或者修改
将走到的路径 - 避免getchar(),
mallocate()这类返回值既可能表示运行正确与否,又能表示具体数值或地址相关的函数定义或实现,如果基础库的代码中有它,尽量避免它;如果设计的库函数中有它,尽量通过返回flag的方式来说明它。 - 尽量避免用地址比较作为判断退出循环的条件,因为地址不确定,存在上溢或者下溢的可能;
- 精确地实现而非近似地实现功能或者函数
- 注意下溢或者上溢:
下溢: short i; i
= -i; (当i=-32768时, short (-
i)还是-32768) - 不要通过移位来替代除法以赚取一点微小的性能优化,因为这样会牺牲代码的清晰度
时间: 2024-07-31 23:09:05