像其他静态代码分析器一样,PVS-Studio通常会产生误报。 但是不要急于考虑奇怪的回答是错误的。 这是一个简短的故事,讲述了PVS-Studio如何再次吸引更多人的注意力。
用户写信支持我们,声称分析仪每行代码立即产生四个误报。 该信最初是给叶夫根尼·雷日科夫(Yevgeny Ryzhkov)的支持,后者在流畅阅读并没有注意到异常反馈的情况下,立即将其发送给首席开发商Svyatoslav Razmyslov。 Eugene没有查看代码,因此只将一半的程序员算在内就可以了。
斯维亚托斯拉夫(Svyatoslav)看了这封信,并怀疑分析仪可能是如此严重的错误。 因此,他来找我咨询。 Svyatoslav希望我定下来,我会注意到一些东西,告诉我分析仪为什么发布所有这些奇怪的消息。 不幸的是,我只确认消息真的很奇怪,不应该这样。 但是,它们发生的原因是什么,我不知道。 决定在Bugtracker中打开任务并开始了解出了什么问题。
只有当Svyatoslav开始制作综合示例以详细描述Bugtracker中的问题时,他才有了见识。 现在,让我们看看您是否可以快速找到分析仪显示4条消息的原因。
这是这封信的文本,经作者许可出版。 这封信附有一张解释性图片。
这里的V560警告全都是假的。 与最新版本的PVS-Studio一起运行以供个人使用。 基本上,“ IF”语句是正确的。 外层是为了提高速度-内层还是需要的,非内层总是对或错。
亲爱的读者,现在,您有时间进行自我测试! 看到错误了吗?
您的时间要专心。 独角兽会稍等。
在本文的引言部分之后,很可能许多人发现了一个错误。 配置为查找错误时,将定位该错误。 阅读这封信后,发现它被称为“误报”的错误就更容易了:)。
现在为那些懒得寻找错误的人提供一个解释。 再次考虑条件:
if (!((ch >= 0x0FF10) && (ch <= 0x0FF19)) || ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) || ((ch >= 0x0FF41) && (ch <= 0x0FF5A)))
该代码的作者计划验证该字符不属于这三个范围中的任何一个。
错误是逻辑NOT运算符(!)仅适用于第一个子表达式。
如果满足条件:
!((ch >= 0x0FF10) && (ch <= 0x0FF19))
然后根据
短路评估中断表达式
评估 。 如果不满足条件,则变量
ch的值在[0xFF10..0xFF19]范围内。 因此,四个进一步的比较是没有意义的。 所有这些都是错误的或真实的。
再来一次 请参阅,如果
ch在
[0xFF10..0xFF19]范围内并且继续计算,则:
- ch> = 0x0FF21-始终为false
- ch <= 0x0FF3A-始终为true
- ch> = 0x0FF41-始终为false
- ch <= 0x0FF5A-始终为true
这就是PVS-Studio分析仪所警告的。
因此,静态分析器比用户和我们团队中的两个半程序员更专注。
要解决这种情况,您需要添加其他括号:
if (!(((ch >= 0x0FF10) && (ch <= 0x0FF19)) || ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) || ((ch >= 0x0FF41) && (ch <= 0x0FF5A))))
或重写条件:
if (((ch < 0x0FF10) || (ch > 0x0FF19)) && ((ch < 0x0FF21) || (ch > 0x0FF3A)) && ((ch < 0x0FF41) || (ch > 0x0FF5A)))
但是,我不建议您使用任何这些选项。 我写这个来简化阅读代码:
const bool isLetterOrDigit = (ch >= 0x0FF10 && ch <= 0x0FF19)
请注意,我删除了一些括号。 正如我们所看到的,大量的括号根本无法避免错误。 括号应该使阅读代码更容易,而不是更复杂。 程序员应该记住,比较的优先级= <,=>比&&运算符的优先级高。 因此,这里不需要括号。 但是,如果您问&&或||是哪个优先级,则很多人会感到困惑。 因此,要指定计算顺序&&,|| 括号最好放。
为什么写||更好 一开始,我在文章“
编程,重构以及所有这些的主要问题 ”中进行了介绍(请参阅章节:将相同类型的代码与“表”对齐)。
谢谢大家的关注。 下载并开始使用
PVS-Studio 。 这将有助于尽早识别出许多错误和潜在的漏洞。

如果您想与说英语的读者分享这篇文章,请使用以下链接:Andrey Karpov。
如何证明PVS-Studio比三个半程序员更具吸引力 。