如果(flag == 0)或if(0 == flag),哪一个执行速度会更快?
面试问题: if (flag==0)
或if (0==flag)
,哪一个执行得更快? 为什么?
我还没有看到任何正确的答案(已经有一些) 警告:纳瓦兹指出了用户定义的陷阱 。 我后悔自己在“愚蠢的问题”上匆忙地投了弃权票,因为看起来很多人没有把握得很好,给编译器优化提供了一个很好的讨论空间:)
答案是:
什么是
flag
的types?
在flag
实际上是用户定义types的情况下。 那么这取决于operator==
哪个超载被选中。 当然,这看起来很愚蠢,他们不会是对称的,但肯定是允许的,我已经看到了其他的弊端。
如果flag
是一个内置的,那么两者应该采取相同的速度。
从x86
上的维基百科文章中,我会为if
语句的下一个Jxx
指令打赌:也许是一个JNZ
(如果不是零),或者等价的。
我怀疑编译器会错过这样一个明显的优化,即使优化已closures。 这是Peephole Optimization针对其devise的types。
编辑:再次popup,所以让我们添加一些程序集(LLVM 2.7 IR)
int regular(int c) { if (c == 0) { return 0; } return 1; } int yoda(int c) { if (0 == c) { return 0; } return 1; } define i32 @regular(i32 %c) nounwind readnone { entry: %not. = icmp ne i32 %c, 0 ; <i1> [#uses=1] %.0 = zext i1 %not. to i32 ; <i32> [#uses=1] ret i32 %.0 } define i32 @yoda(i32 %c) nounwind readnone { entry: %not. = icmp ne i32 %c, 0 ; <i1> [#uses=1] %.0 = zext i1 %not. to i32 ; <i32> [#uses=1] ret i32 %.0 }
即使不知道如何阅读投资者关系,我认为这是自我解释。
与GCC 4.1.2的amd64相同的代码:
.loc 1 4 0 # int f = argc; movl -20(%rbp), %eax movl %eax, -4(%rbp) .loc 1 6 0 # if( f == 0 ) { cmpl $0, -4(%rbp) jne .L2 .loc 1 7 0 # return 0; movl $0, -36(%rbp) jmp .L4 .loc 1 8 0 # } .L2: .loc 1 10 0 # if( 0 == f ) { cmpl $0, -4(%rbp) jne .L5 .loc 1 11 0 # return 1; movl $1, -36(%rbp) jmp .L4 .loc 1 12 0 # } .L5: .loc 1 14 0 # return 2; movl $2, -36(%rbp) .L4: movl -36(%rbp), %eax .loc 1 15 0 # } leave ret
在你的版本中没有区别。
我假设标志的type
不是用户定义types,而是一些内置types。 枚举是例外! 。 您可以将枚举视为内置对象。 实际上,它的价值是内buildtypes之一!
如果是用户定义的types( enum
除外),那么答案完全取决于你如何重载operator ==
。 请注意,您必须通过定义两个函数来重载==
,每个版本都有一个函数!
绝对没有区别。
但是,通过参考消除任务/比较拼写错误,您可能会在回答这个面试问题时获得积分:
if (flag = 0) // typo here { // code never executes } if (0 = flag) // typo and syntactic error -> compiler complains { // ... }
虽然这是事实,例如C编译器会在前者( flag = 0
)的情况下发出警告,但在PHP,Perl或Javascript或<insert language here>
都没有这样的警告。
速度方面绝对没有差别。 为什么要这样?
那么当flag是一个用户自定义的types时是有区别的
struct sInt { sInt( int i ) : wrappedInt(i) { std::cout << "ctor called" << std::endl; } operator int() { std::cout << "operator int()" << std::endl; return wrappedInt; } bool operator==(int nComp) { std::cout << "bool operator==(int nComp)" << std::endl; return (nComp == wrappedInt); } int wrappedInt; }; int _tmain(int argc, _TCHAR* argv[]) { sInt s(0); //in this case this will probably be faster if ( 0 == s ) { std::cout << "equal" << std::endl; } if ( s == 0 ) { std::cout << "equal" << std::endl; } }
在第一种情况下(0 == s),转换运算符被调用,然后将返回的结果与0进行比较。在第二种情况下调用==运算符。
如果有疑问,可以对其进行评估并了解真相。
速度应该完全相同。
但是请注意,有些人在等式比较(所谓的“Yoda条件”)中使用左常数来避免所有可能出现的错误,如果你写=
(赋值运算符)而不是==
(相等比较运算符); 由于分配给一个文字触发了一个编译错误,这种错误是可以避免的。
if(flag=0) // <--- typo: = instead of ==; flag is now set to 0 { // this is never executed } if(0=flag) // <--- compiler error, cannot assign value to literal { }
另一方面,大多数人认为“尤达条件”看起来很怪,很烦人,尤其是因为使用适当的编译器警告,他们所预防的错误类也可以被发现。
if(flag=0) // <--- warning: assignment in conditional expression { }
正如其他人所说,没有任何区别。
0
必须被评估。 flag
必须被评估。 这个过程需要同一时间,不pipe他们放置哪一边。
正确的答案是:他们都是一样的速度。
即使expression式if(flag==0)
和if(0==flag)
也具有相同数量的字符! 如果其中的一个写成if(flag== 0)
,那么编译器将有一个额外的空间来parsing,所以在指出编译时间时你会有一个合理的理由。
但是既然不存在这样的事情,那么绝对没有理由为什么要比别人快。 如果有一个原因,那么编译器正在做一些非常非常奇怪的事情来生成代码…
哪一个的速度取决于你使用哪个版本的==。 这里有一个代码片段,它使用了2个可能的==实现,取决于你是否select调用x == 0或者0 == xselect了2中的一个。
如果你只是使用POD,那么速度真的不重要。
#include <iostream> using namespace std; class x { public: bool operator==(int x) { cout << "hello\n"; return 0; } friend bool operator==(int x, const x& a) { cout << "world\n"; return 0; } }; int main() { x x1; //int m = 0; int k = (x1 == 0); int j = (0 == x1); }
那么,我完全同意OP在评论中所说的一切:
如果编译器不够聪明(确实不应该使用它),或者禁用了优化,那么x == 0
可以编译为本地程序集jump if zero
指令),而0 == x
可能是更通用的(并且代价高昂)数值的比较。
不过,我不想为一个以这些词汇来思考的老板工作……
在执行速度方面肯定没有区别。 两种情况下都需要以相同的方式评估这种情况。
我认为最好的答案是“这个例子是什么语言”?
这个问题没有指定语言,它被标记为“C”和“C ++”。 准确的答案需要更多的信息。
这是一个糟糕的编程问题,但它可能是一个很好的迂回的“让受访者足够的绳索,要么上吊自己,要么build立一个swing”部门。 这些问题的问题在于,他们通常会从面试官到面试官logging下来,直到find从各个angular度不能真正理解的人。
使用build议的方法构build两个简单的程序。
组装代码。 看看大会,你可以判断,但我怀疑是有区别的!
面试比以往任何时候都要低。
正如一边(我实际上认为任何体面的编译器会使这个问题没有意义,因为它会优化它)使用0 ==旗帜旗帜== 0确实可以防止你忘记其中一个= =的错字(例如,如果你意外地键入flag = 0它会编译,但是0 = flag不会),我认为这是每个人在某个点上犯的一个错误…
如果有什么不同,停止编译器select更快一次? 所以从逻辑上讲,不能有任何区别。 这大概就是面试官所期望的。 这实际上是一个很好的问题。