翻译《有关编程、重构及其他的终极问题?》——4.小心--操作符,请把表达式放在括号中
来源:互联网 发布:oracle查看数据库 编辑:程序博客网 时间:2024/04/27 18:15
翻译《有关编程、重构及其他的终极问题?》——4.小心?:操作符,请把表达式放在括号中
标签(空格分隔): 翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
校验者:高国栋
最后更新:2016年12月04日
本书背景说明、总目录等介绍,可以跳转到以下链接进行查看:
http://blog.csdn.net/headman/article/details/53045891欢迎大家转载,但请附上原作者以及翻译者的名字、原文出处,以尊重光荣的劳动者。
4.小心?:操作符,请把表达式放在括号中
这次我们从Haiku项目(从BeOS继承的项目)选取代码,PVS-Studio检测到的错误是:V502 Perhaps th ‘?:’operator works in a different way than it was expected. The ‘?:’ operator has a lower priority than the ‘-’ operator(译者注:大意是说这个?运算符优先级比-运算符低,所有可能表达式并非写代码的人所期望的).
bool IsVisisble(bool ancestorsVisible) const{ int16 showLevel = BView::Private(view).ShowLevel(); return (showLevel - (ancestorsVisible) ? 0 : 1) <= 0;}
解释
如果我们去查看C/C++运算符优先级,我们会发现三元运算符?:有很低的优先级,甚至比/,+,<等运算符的优先级还低。所以,上面的代码就没有按照编写者预想的方式工作。
那个编写者设想:?运算符会按照下面的方式执行:
(showLevel - (ancestorsVisible ? 0 : 1)) <= 0
但是这个表达式实际上是按照下面的方式执行的:
((showLevel - ancestorsVisible) ? 0 : 1) <= 0
这个错误发生在非常简单的代码中,这说明了?:操作符有多危险。当使用?:操作符时,很容易犯错误,而且在更复杂的情况立,对代码也是一种纯粹的伤害:它不光是让你犯错误,而且还会让你的代码非常难读。
真的得小心的使用?:运算符。我见过很多bug都和这个运算符的使用有关。
正确的代码
return showLevel - (ancestorsVisible ? 0 : 1) <= 0;
建议
在我之前写的文章里,我们已经讨论了三元运算符所带来的问题,而且从那时起我对这些问题也变得更敏感。上面的例子也说明了之类的运算符是多么容易带来问题,即使实在很短且简单的表达式中,因此我会修改我在之前写的文章中的建议。
我不是建议完全不使用?:运算符。其实它是有用的,甚至在某些情况下是必须的。但是,请一定不要过度使用它,一旦你决定使用它,请看看我的建议:
一定要把三元运算符表达式放在括号里。假设你有如下表达式:
A = B ? 10 : 20;
你应该写成这样:
A = (B ? 10 : 20);
是的,这个括号有些多余,但当你的同事以后在重构中在这个表达式中增加其他变量时,它会保护你的代码:
A + X + (B ? 10 : 20);
如果没有括号,你可能会忘掉?:运算符是低优先级的,然后偶尔某个时候你的程序就出问题了……虽然有了额外的保护,但如果你把“X+”写在括号里面了,这样就会导致同样的错误。
- 翻译《有关编程、重构及其他的终极问题?》——4.小心--操作符,请把表达式放在括号中
- 翻译《有关编程、重构及其他的终极问题?》——11.不要试图把尽量多的操作符放到一行代码里
- 翻译《有关编程、重构及其他的终极问题?》——6.当把一个指针明确的转换为整型时,请检查所有相关代码
- 翻译《有关编程、重构及其他的终极问题?》——7.不要在循环中调用alloca()函数
- 翻译《有关编程、重构及其他的终极问题?》——26.潜伏的VARIANT_BOOL
- 翻译《有关编程、重构及其他的终极问题?》——前言
- 翻译《有关编程、重构及其他的终极问题?》——16.在编程过程中“装逼”是不可接受的
- 翻译《有关编程、重构及其他的终极问题?》——15.在你的代码中开始使用enum class吧
- 翻译《有关编程、重构及其他的终极问题?》——31.在C-C++中数组不是值传递的
- 翻译《有关编程、重构及其他的终极问题?》——1. 别把编译器的事给做了
- 翻译《有关编程、重构及其他的终极问题?》——29.在迭代器上请使用前置自增操作符(++i),不要使用后置自增操作符(i++)
- 翻译《有关编程、重构及其他的终极问题?》——5.使用工具去分析你的代码
- 翻译《有关编程、重构及其他的终极问题?》——10.避免使用多个小的#ifdef块
- 翻译《有关编程、重构及其他的终极问题?》——13.表格化的格式化
- 翻译《有关编程、重构及其他的终极问题?》——17.使用专门的函数清除专有数据
- 翻译《有关编程、重构及其他的终极问题?》——23.自动获取字符串的长度
- 翻译《有关编程、重构及其他的终极问题?》——27.狡猾的BSTR字符串
- 翻译《有关编程、重构及其他的终极问题?》——9.使用'-0'符号作为结尾标记
- Android输入事件详解
- Rxjs基础
- 在eclipse中导入其他项目可能会出现import javax.servlet.http.*;报错,解决方案如下:
- java将二进制数转化为十进制数
- String与StringBuffer与StringBuilder
- 翻译《有关编程、重构及其他的终极问题?》——4.小心--操作符,请把表达式放在括号中
- POJ 2036 Wireless Network
- java核心技术----Object类
- SDL_PollEvent函数
- 深度探索c++对象模型之template中的名称决议方式
- android手指个数识别项目
- 解决listview焦点抢夺问题
- Activity生命周期
- Android自定义UI实战(基础篇3)---图标圆弧运动