翻译《有关编程、重构及其他的终极问题?》——14.一个好的编译器和代码风格还不够

翻译《有关编程、重构及其他的终极问题?》——14.一个好的编译器和代码风格还不够

标签(空格分隔): 翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2017年01月10日


14.一个好的编译器和编码风格还不够

我们已经说过优秀的编码风格的事,但这次我们将看一下反例。好的编码风格并非万能药,还会有些各种各样的错误是优秀的编码风格不能解决的。

下面这段代码来自PostgreSQL项目。PVS-Studio诊断的错误描述为:V575 The ‘memcmp’ function processes ‘0’ elements. Inspect the third argument(译者注:大意是说‘memcmp’函数处理了‘0’个元素,请检查此函数的第三个参数)。

Cppcheck分析器也能检查到类似的错误。一般它会发出一个警告:memcmp()函数的第三个参数是无效的,需要一个非布尔值。

Datum pg_stat_get_activity(PG_FUNCTION_ARGS)
{
  ....
  if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
             sizeof(zero_clientaddr) == 0))
  ....
}

解释
上面的代码中,一个右括号放在了错误的位置。虽然这只是个输入错误,但不幸的是,这完全改变了代码的本意。

因为任何对象的大小都是大于0 的,所以sizeof(zero_clientaddr) == 0这个语句一直返回‘false’。false的值为0,这导致memcmp函数比较了0个字节。接下来,这还导致因为函数返回0,因为任意两个数组比较0个字节都是相等的。所以,这段代码可以缩写为if (false)。

正确的代码

if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
           sizeof(zero_clientaddr)) == 0)

建议
这个只是一个没有任何编码技巧可以避免输入错误的例子。我能想到的只有“Yoda表达式”,把常量写在比较操作符的左边:

if (0 == memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
                sizeof(zero_clientaddr)))

但我不推荐这种风格。我不喜欢也不会用这种风格,主要有两个原因:

首先,折让条件判断可读性更差。我不知道如何准确的描述,但它被称为Yoda不是没有原因的。

第二,如果我们把括号放错了位置,它也无能为力。很多原因可以导致你犯错。这里有一个例子,也说明了Yoda表达式并不能避免不正确的括号位置:

if (0 == LoadStringW(hDllInstance, IDS_UNKNOWN_ERROR,
        UnknownError,
        sizeof(UnknownError) / sizeof(UnknownError[0] -
        20)))

上面这段代码来自ReactOS项目。这个错误很难被注意,所以让我来指出来:sizeof(UnknowError[0] - 20)。

所以Yoda表达式在这里也无能为力。

我们可以发明一些造作的方式去保证每一个右括号和左括号正确对应。但这会使得代码太臃肿和丑陋,并且没有人愿意写那样的代码。

所以,再次的,我得说,我没有什么建议的编码风格可以避免右括号放错位置。

那么,这时难道编译器不该出来警告我们关于这些奇怪的结构吗?恩,编译器的确应该,但一般来说没有这么做。我使用的是Visual Studio 2015,指定了/Wall开关……但是没有得到任何警告。但我们不应该去抱怨编译器,因为它还有更多其他更重要的工作要做。

所以这里,我们得到了最重要结论,那就是优秀的编码风格或者编译器(我喜欢VS2015的编译器)不能一直为我们解决以上问题。我时常听到类似的声明:“你只需要把编译器设置成最高的水准以及使用好的编码风格,那么所有东西都会OK的”,不,并非如此。我这里不是说一些程序员在编码上不好;我只想说每个程序员都会犯错误——每个人,没有意外。很多你的输入错误都会偷偷的绕过编译器和优秀的代码风格。

所以好的编码风格和编译器警告的组合非常重要,但并非无所不能。那就是为什么我们需要使用一套各种各样的问题搜索方法。这不是银弹;但多种技术方法的组合可以实现高质量的代码。

我们所讨论的那些错误可以被以下这些方法发现:

  • 代码审查;
  • 单元测试;
  • 手动测试;
  • 静态代码分析;
  • 等等……

我觉得,你应该已经猜想到我个人对静态代码分析最感兴趣。顺便说下,因为可以在最早阶段(比如,刚写完代码)检查到错误,所以静态代码分析是解决特定问题的最佳方法。

事实上,这些错误还能被诸如Cppcheck或者PVS-Studio等工具轻易的发现。

结论
一些人应该还没有理解即使拥有熟练的技巧,其实还不足以避免错误。每个人都犯错……这不可避免。即使是超级专家也时常犯下愚蠢的输入错误。那么既然不可避免,抱怨程序、编译器、编码风格就没有什么用,以后也不会游泳。想法,我们应该使用多种质量提高的工具来解决这些问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值