面试问题:哪个执行速度更快,if (flag==0)
或者if (0==flag)
?为什么?
if(flag = 0)
以一些易读性为代价来确保避免出现bug 。
面试问题:哪个执行速度更快,if (flag==0)
或者if (0==flag)
?为什么?
if(flag = 0)
以一些易读性为代价来确保避免出现bug 。
Answers:
我还没有看到任何正确的答案(并且已经有一些警告):Nawaz确实指出了用户定义的trap。而且我很遗憾我仓促对“最愚蠢的问题”投了赞成票,因为似乎很多人都没有把它弄对,并且它为进行有关编译器优化的美好讨论提供了空间:)
答案是:
什么是
flag
类型?
如果flag
实际上是用户定义的类型。然后,取决于operator==
选择哪个过载。当然,它们不是对称的,这似乎很愚蠢,但这是允许的,而且我已经看到了其他滥用情况。
如果flag
是内置的,则两者应采用相同的速度。
在Wikipedia上的文章中x86
,我押注Jxx
该if
语句的指示信息:可能是JNZ
(如果不是零,则跳转)或等效形式。
我怀疑即使关闭了优化功能,编译器也会错过如此明显的优化功能。这是为“ 窥孔优化”设计的。
编辑:再次出现,所以让我们添加一些程序集(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
}
即使不知道如何阅读投资者关系,我也认为这是不言而喻的。
flag
必须为整数或布尔值。OTOH,具有flag
用户定义类型的变量名称本身是非常错误的,恕我直言
#include
指令也可以使用它。为简单起见,通常达int
,char
,bool
等。所有其他类型被认为是用户定义的,那就是它们的存在,因为他们有一些用户他们宣称的结果:typedef
,enum
,struct
,class
。例如,std::string
是用户定义的,即使您自己当然也没有定义它:)
与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
of标志不是用户定义的类型,而是某种内置类型。枚举是例外!。您可以将枚举视为内置枚举。实际上,它的值是内置类型之一!
如果是用户定义的类型(除外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>
。
速度方面绝对没有区别。为什么要有?
x == 0
可以使用它,但0 == x
可以使用普通比较。我的确曾说过,这将不得不加以限制。
virtual operator==(int)
用户定义的类型?
那么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进行比较。在第二种情况下,将调用==运算符。
如有疑问,请对其进行基准测试并了解事实。
它们在速度方面应该完全相同。
但是请注意,有人在等式比较(通常称为“ 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
{
}
另一方面,大多数人发现“ Yoda条件”看起来很奇怪和烦人,特别是因为使用适当的编译器警告也可以发现他们防止的错误类别。
if(flag=0) // <--- warning: assignment in conditional expression
{
}
哪种速度取决于您使用的==版本。这是一个使用==的2种可能实现的代码段,具体取决于您是选择调用x == 0还是0 == x来选择其中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);
}
在执行速度方面肯定没有区别。在两种情况下都需要以相同的方式评估条件。