关于如何扩展复杂且难懂的C代码的一点经验谈
有时,我们会希望扩展一些现有的C代码。这些代码可能经历了相当久的运行考验——它们至少目前工作起来没有问题——然而,它们可能存在各种各样的问题,比如:
- 缺少注释。
- 过分使用的goto语句。
- 变量名不规范。
- 逻辑复杂难懂。
- 过分使用表达式赋值(if (foo = bar()) {})
- 直接返回函数返回值(这是合法的,但会给增加功能带来困难)
要扩展这类代码是一件有挑战的事情。
想要扩展这类代码,我认为应该首先有下面的一些想法:
- 我们要做的是扩展,而不是全盘重构。
- 触及设计结构的修改,应尽可能避免。
- 「浅尝辄止」,即,避免侵入式的修改。尽可能将修改封装为独立的单元。
- 「避免恶化」,即,避免设计进一步恶化。
在修改代码时,可以采用的一些方法:
追踪数据的使用
通常我们的扩展会用到程序中的某些数据。在真的开始使用之间,要确认:(1)这些数据没有在我们不希望的时候被读写(2)我们添加的代码没有在程序不希望的时候读写这些数据;如果需要,复制这些数据,但是,此时需要确认没有引入新的内存泄漏。添加断言(asserts)并观察控制流
有年头的程序往往会使用一些令人作呕的技巧。例如,有些变量可能并不简单地用来保存程序注释中所表现的功能,比如它们可能还兼做状态。我的建议是,如果不是在对程序进行重构,那么很重要的一点就是避免触发这类代码产生不希望的行为。
一种有效的确认方法就是增加断言。在程序中增加严厉的断言,有助于帮助你理解程序的逻辑,从而减少引入错误的可能。
编写单元测试
程序的主要逻辑,在扩展前后不应产生超出我们预期的变化。通过编写单元测试,并观察程序扩展前后的测试结果,有助于减少发生错误的可能性。清理加入的代码
在完工时,应把插入的断言删掉,简化代码,并交给另一个人复审。