delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

18 Feb 2006

关于如何扩展复杂且难懂的C代码的一点经验谈

有时,我们会希望扩展一些现有的C代码。这些代码可能经历了相当久的运行考验——它们至少目前工作起来没有问题——然而,它们可能存在各种各样的问题,比如:

  • 缺少注释。
  • 过分使用的goto语句。
  • 变量名不规范。
  • 逻辑复杂难懂。
  • 过分使用表达式赋值(if (foo = bar()) {})
  • 直接返回函数返回值(这是合法的,但会给增加功能带来困难)

要扩展这类代码是一件有挑战的事情。

想要扩展这类代码,我认为应该首先有下面的一些想法:

  • 我们要做的是扩展,而不是全盘重构。
  • 触及设计结构的修改,应尽可能避免。
  • 「浅尝辄止」,即,避免侵入式的修改。尽可能将修改封装为独立的单元。
  • 「避免恶化」,即,避免设计进一步恶化。

在修改代码时,可以采用的一些方法:

  • 追踪数据的使用
    通常我们的扩展会用到程序中的某些数据。在真的开始使用之间,要确认:(1)这些数据没有在我们不希望的时候被读写(2)我们添加的代码没有在程序不希望的时候读写这些数据;如果需要,复制这些数据,但是,此时需要确认没有引入新的内存泄漏。

  • 添加断言(asserts)并观察控制流
    有年头的程序往往会使用一些令人作呕的技巧。例如,有些变量可能并不简单地用来保存程序注释中所表现的功能,比如它们可能还兼做状态。我的建议是,如果不是在对程序进行重构,那么很重要的一点就是避免触发这类代码产生不希望的行为。

一种有效的确认方法就是增加断言。在程序中增加严厉的断言,有助于帮助你理解程序的逻辑,从而减少引入错误的可能。

  • 编写单元测试
    程序的主要逻辑,在扩展前后不应产生超出我们预期的变化。通过编写单元测试,并观察程序扩展前后的测试结果,有助于减少发生错误的可能性。

  • 清理加入的代码
    在完工时,应把插入的断言删掉,简化代码,并交给另一个人复审。