我倾向于使用逻辑否定运算符编写if语句:
我周围的一些人倾向于使用显式比较,因此代码看起来像:
1 2
| if (FOO == p)
some_code(); |
其中foo是false、false、0、0.0、null等之一。
我喜欢简短的表格,因为它是:
- operator!=友好型
- generic programming友好型
- 简洁(对我来说更美)
写这篇文章(如果有的话)的实际好处是什么?
- 我不认为你会得到一个非主观的答案。
- 在我看来,与真假直接比较的人应该被解雇/以其他方式避免。
- @希斯·亨尼克特:尤其是当他们把一个指针与true或false作比较时!
- 奇怪的是,没有提到泛型函数的注释,其中!p引入了对p类型的一种需求。
- @Mike Mueller:我想试一试,如果有答案可以帮助我进行代码评审辩论(这很少见,但有时会发生),我会接受的。你知道,就像"主观的,但对我和所有那些我拒绝承诺的人都有效":—)
- 我刚刚意识到,在我看来,这是一个有趣的误解:那些认为显式表达式使代码更像readable的人倾向于认为,通过指定一个显式值,他们会给读者一个提示,说明p的实际类型,就好像一眼文字就给了你足够的信息来猜测它的类型。我要强调这两个相反的论点:(1)从字面上猜测类型不超过猜测(与假设一样糟糕);(2)最好编写代码,这样读者就不必猜测EDOCX1的类型了(4)
- @希思——我经常想知道,为什么和真正的相比,人们只停留在一个。毕竟,如果if (x == true)比if (x)好,那么if ((x == true) == true)不是更好吗?
为了对比@erik的答案,我会说使用!来提高可读性。如果你发现你忽视了它,那就去检查你的眼睛。下一步是什么?避免1,改用3-2?
- 大声笑!让我想起一台机器,我们用PI/PI表示"一"表示存储效率,因为它所用的时间小于数字串1。
- @特劳巴杜:我们在这里也有类似的想法——对我来说,规则readable包含了"目前不需要提供细节"的子规则。
- 显然,如果读者忽视了!p中的!,那么唯一明智的做法就是写!!!p。多个感叹号可以在互联网上使用,它们也可以在代码中使用。
- 如果(!)(P?假?)
- 我认为在复合条件下很容易过度查找,但这可能是内部解析器缺陷:)
- @Troubadour:我认为(作为@glowcoder)虽然对于布尔和指针,我可以发现它是自然的,对于整数,它取决于整数可以隐式转换为布尔的事实,因此我宁愿看到p != 0。
- 我完全同意Troubadour(我用+1表示)。但是,尽管这个答案很受欢迎,但我不能接受它,因为问题是用另一种方式做它的好处(即使好处是神话般的)。
- @Matthieu M.:我同意!只适用于指针和胸部,我是@glowcoder答案的早期支持者。我必须承认,我的答案写得更多的是"是我吗?"关于!的可读性问题,我错误地忽略了这一点。
这取决于p代表什么。
如果p代表一个布尔值/逻辑值,那么(!p)似乎最合适-与"假"相比通常是不鼓励的。我不认为这会有什么争论。
如果p代表一个值,比如计数器,那么(p == 0)或(0 == p)似乎是合适的。(通常两人之间会有激烈的辩论。我发现第一个更易读,但第二个避免了一些非常严重的错误。)除了两个选项中的哪一个更好,我不认为这是一个辩论(如中所述,它应该与0相比)。
如果p代表一个指针,那么就有一些问题。一个有能力的C++程序员应该知道,EDCOX1 7将告诉你它是否为空。然而,这篇文章的可读性是一个灰色地带,我认为这是一个有争议的争论。
- 关于严重的错误——>严重的编译器会警告在条件下的意外分配。+1用于不同地处理布尔整数和指针。对于指针,C++ 0x将建议p != nullptr。
使用(0 == p)或(p == 0)以提高可读性。乍一看,!比== 0更容易被忽视。
如果您有忽略编译器警告的习惯,并且希望知道何时使用=而不是==,请使用(0 == p)。
- 这里的readability概念有一个缺陷——读卡器可能会对p的类型做出错误的假设,例如,读卡器可能会在它是整数或双精度时使用指针,因此这种可读性的下一步将是hungarian notation。
- 您应该使用一个明确指示类型的常量,我只是没有使用0.0、nullptr或null复制粘贴上面的内容。
- 实际上,我发现if (p)和if (!p)比if (p == 0)、if (p == 1)或if (p != 0)更容易阅读。
- @丹,如果p是bool类型,我只会发现它更可读。否则我更喜欢将其转换为bool的支票。它几乎和使用的人一样糟糕!!p测试类对象的真实性。
- if (! p)应该足以让人们认识到"不"。
- +1,我发现人们倾向于读"P做(或不做)等于真"比"不P"更正确。即使在英语中,我们也倾向于说"如果开关是关闭的,那么……"而不是"如果开关不是打开的,那么……"
- @埃里克:如果你有忽视警告的习惯,就打开-Werror。
- @马修:我没有,但不幸的是很多人都有。
- @当然,对于非布尔型和非指针型,我实际上使用if (p == NUMBER),因为我觉得它更好地体现了我的意图。我总是使用if (p)或if (! p)(就像用户未知,我确实在两者之间放置了一个空间!)对于布尔值和测试指针是否为空时(读取为"如果指针有效/无效",而不是"如果指针等于零/空")。
- 我知道我是一个异教徒(我的代码可能看起来很难看),但几年前,我硬要自己在任何分配操作(a=b=0;b+=1)之前永远不要离开空白,并且总是在比较运算符(a==b)之前使用空白。从那以后,我就再也没有掉进"="而不是"="的陷阱。
有人声称,如果你明确地比较NULL、FALSE、0等,程序员会发现它更容易理解,而逻辑运算符可能会让不理解隐式转换和布尔运算在C/C++中如何工作的人感到困惑。
(免责声明:我本人不分享此观点。EDCOX1、0和EDCOX1、1是C和C++中表达的惯用方式,理解困难的程序员不需要触摸C或C++代码。希思·亨尼克特的评论毫无新意。)
- 虽然有很多好的评论-这个答案是关于原始问题最好的。它讲述了"一些程序员"所看到的好处,也就是说,有一大群其他人(包括我)没有看到这样的好处。
if (!Foo)版本的一个尚未提及的好处是,它将与使用安全bool习惯用法的类一起使用。在实现这一点的类中,类的比较运算符将失败(例如,Foo==0将不定义),但!Foo将在foo上调用转换运算符,返回指向成员函数的指针(如果Foo应被视为false,则返回空指针)。许多boost类,比如shared-ptr,都使用这种技术。
就个人而言,我对从int到boolean的隐式转换有点厌烦。我认为它对C语言不再有什么帮助。在没有布尔类型的C89中,使用整数作为布尔值是完全合理的,在这种情况下,转换会导致代码美观。我明白了为什么它不能被删除,尤其是在处理由于兼容性原因不能更改为返回布尔值的库时,现在有了一个。但我当然不认为在所有情况下都应该使用它。
有时,0整数值表示"没有一个",但有时表示"有一个,它是零"。所以我很高兴:
1 2 3 4 5 6 7
| users = get_number_of_users();
if (users) {
// there are users
...
} else {
// there aren't users
} |
我一点也不喜欢:
1 2 3 4 5 6
| length = strlen(ptr);
if (length) {
// there is length? OK, sort of...
} else {
// there isn't length? No, wait, there *is* a length, that length is 0
} |
所以你写if (length == 0)比if (!length)更为实际。""如果不是长度"在英语中没有意义,那么也不一定要用代码编写什么。
不可否认,0是作为一个特殊的地方持有者被发明的,意思是"没有任何地方"。但是,认识到在许多情况下,它可以被当作一个数字来对待,这是数学史上的一个重要突破,我认为我们不应该仅仅因为C为我们提供了一个语法来重新专门对待它,就放弃它;-)如果你想知道一个数是否是5,你可以将它与5进行比较,通常我会瘦一些。k相同的值应保持为0。
- 惯用的if (!p || !*p)在英语中也没有意义,但并不意味着任何人都应该停止使用它。如果程序员想要用英语编码,他最好使用PASCAL而不是C/C++。
- @安德烈:不过,考虑到这两种选择之间几乎没有选择余地,我们必须基于一些小理由来选择。也许你更喜欢if (!length)。我比较喜欢if (length==0)。我认为我喜欢它的原因是我发现它更直接地表达了我的意图。另外,我尽量不使用if (!p || !*p)。如果我对空字符串的空指针执行相同的操作,那么为什么我的数据方案允许这种冗余出现呢?有时候这是不可避免的,有时候你可以修复它。
- 你在考虑中加入了if (length)——这种形式已经够糟糕了。请注意,最初的问题只涉及惯用的if (!length)形式,我在所有上下文中都非常熟悉。我更喜欢它,而不是含糊不清的0==x/x==0。
如果语言是c,如果p是指针,那么if(p)和if(!p)应避免。
C(语言)没有指定空指针将是布尔值false。它确实表示,强制转换为指针(隐式或显式)的0将给出空指针。
因此,测试p而不是p==null并不一定是相同的,而且在一些较旧的硬件上,它们肯定是不同的,因为null指针实际上是指向特定内存页的指针。
但是,您可以保证0和因此空值等于空指针,因为C说它们必须是。
- PS:我不知道如何应用C++
- C99,6.5.5.3P5表达!e等于(0==e)。c99,6.5.9p5如果一个操作数是指针,另一个操作数是空指针常量,则将空指针常量转换为指针类型。c99,6.3.2.3p3值为0的整数常量表达式或转换为void*类型的表达式称为空指针常量。
我会在前后放置一个空间!:( ! p)所以!脱颖而出。但我将把这种用法限制为只包含指针的整数类型。我将使用==作为浮点,因为它将使您和其他人暂停并思考0.0 == p是否真的适合指定公差。
如果p是一个类的实例,那么应该通过定义操作符来使用( ! p)!避免与0.0 == p的隐式转换。
- 好的,如果作为原始代码作者,您知道p提供operator!=,该怎么办?
- @安德烈,我会更新我的回复。
在非常复杂的条件中,使用显式的==有助于提高可读性。不幸的是,它还打开了写x=0而不是x==0的门,但是您可以通过写0==x来避免这一点(这样0=x将抛出一个错误)。
这也可能是其他语言的习惯,否则你必须强制转换为布尔值。
- 有趣的是,显式比较还会带来附加的括号,使复杂的条件更加复杂。
if (Foo)和if (!Foo)似乎暗示Foo是一个布尔变量,至少对我来说是这样。也就是说,只要您的标识符具有足够的描述性,它就真的不重要了。我将在新代码中使用!Foo,但如果有,请遵循现有的约定。一致性胜过一切。
使用if (0 == p),在这种情况下,您强制比较输入"if scope"。我的意思是,很明显你会想这样做,以防p is equals 0。仅仅使用(!p),你想知道的并不明确。可能是null, false等。
我看到的唯一务实的原因是,在第二种情况下,用于比较的值的类型更加明确。foo==空foo是一个ponter类型,!foo不能说它是指针、bool等)