面试问题:哪一个会执行得更快,if (flag==0)
或if (0==flag)
?为什么呢?
答案 0 :(得分:235)
我还没有看到任何正确答案(并且已经有一些)警告:Nawaz确实指出了用户定义的陷阱。而且我很遗憾我匆匆忙忙抛出“最愚蠢的问题”,因为似乎有很多人没有把它弄好,而且它为编译器优化提供了很好的讨论空间:)
答案是:
什么是
flag
的类型?
在flag
实际上是用户定义类型的情况下。那么它取决于选择operator==
的过载。当然,它们不是对称的似乎是愚蠢的,但它肯定是允许的,我已经看到了其他的滥用。
如果flag
是内置的,则两者都应采用相同的速度。
从x86
Jxx
开始,我打赌if
语句的JNZ
指令:也许是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
}
(如果不是零则跳转) )或某些等价物。
我怀疑编译器错过了这样一个明显的优化,即使关闭优化也是如此。这是为Wikipedia article设计的内容类型。
编辑:再次Sprang up,所以让我们添加一些程序集(LLVM 2.7 IR)
{{1}}
即使一个人不知道如何阅读IR,我认为这是不言自明的。
答案 1 :(得分:56)
您的版本没有任何区别。
我假设标志的type
不是用户定义的类型,而是一些内置类型。 Enum是个例外!。您可以将枚举视为内置的。事实上,它的价值是内置类型之一!
如果是用户定义的类型(enum
除外),则答案完全取决于您如何重载运算符==
。请注意,您必须通过定义两个函数来重载==
,每个函数对应一个函数!
答案 2 :(得分:56)
amd64与GCC 4.1.2的代码相同:
.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
答案 3 :(得分:27)
绝对没有区别。
你可以通过参考消除作业/比较拼写错误来回答那个面试问题,但是:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
虽然这是真的,例如如果是前者(flag = 0
),C编译器会发出警告,PHP,Perl或Javascript或<insert language here>
中都没有这样的警告。
答案 4 :(得分:16)
速度方面绝对没有区别。为什么会这样?
答案 5 :(得分:12)
当flag是用户定义的类型
时,存在差异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进行比较。在第二种情况下,调用==运算符。
答案 6 :(得分:11)
如果有疑问则会对它进行基准测试并了解真相。
答案 7 :(得分:7)
它们在速度方面应该完全相同。
请注意,有些人在等式比较(所谓的“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
{
}
答案 8 :(得分:5)
正如其他人所说,没有区别。
必须对 0
进行评估。必须对flag
进行评估。这个过程需要相同的时间,无论它们放在哪一侧。
正确的答案是:它们的速度都是一样的。
即使表达式if(flag==0)
和if(0==flag)
也有相同数量的字符!如果其中一个被写为if(flag== 0)
,那么编译器将有一个额外的空间来解析,因此你有理由指出编译时。
但由于没有这样的事情,所以绝对没有理由为什么一个人应该比其他人更快。如果有原因,那么编译器正在为生成代码做一些非常非常奇怪的事情......
答案 9 :(得分:5)
嗯,我完全同意所有人在OP的评论中所说的,为了运动起见:
如果编译器不够聪明(实际上你不应该使用它)或者禁用优化,x == 0
可以编译为本机程序集jump if zero
指令,而0 == x
可能是比较数字值的更通用(且代价高昂)。
尽管如此,我还是不想为那些以这些方式思考的老板工作......
答案 10 :(得分:5)
哪一个快速取决于您使用的==版本。这是一个使用2个可能的==实现的片段,并且根据您是否选择调用x == 0或0 == x选择其中一个。
如果您只是使用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);
}
答案 11 :(得分:4)
执行速度方面肯定没有区别。需要以相同的方式评估这两种情况。
答案 12 :(得分:3)
使用建议的方法构建两个简单的程序。
汇编代码。看看大会你可以判断,但我怀疑是否有区别!
采访比以往任何时候都要低。
答案 13 :(得分:3)
我认为最好的答案是“这个例子中的语言是什么?”
问题没有指明语言,它标记为'C'和'C ++'。准确的答案需要更多信息。
这是一个糟糕的编程问题,但它可能是一个很好的狡猾的“让我们给受访者足够的绳索让自己挂起或建立一个树摇摆”部门。这些问题的问题在于,他们通常会被记录下来并从面试官那里传下来,直到面对那些从各方面都不了解的人。
答案 14 :(得分:2)
就像旁边一样(我实际上认为任何体面的编译器都会让这个问题没有实际意义,因为它会优化它)使用0 == flag over flag == 0确实可以防止你忘记其中一个=的错误(即如果你意外地输入flag = 0它会编译,但0 =标志不会),我认为这是每个人在某个时刻做出的错误......
答案 15 :(得分:0)
如果有任何差异,那么什么阻止编译器选择更快一次? 从逻辑上讲,没有任何区别。这可能是面试官所期望的。这实际上是一个很棒的问题。