面试问题:哪一个会执行得更快,if (flag==0)或者if (0==flag)?为什么?
Mat*_* M. 235
我还没有看到任何正确答案(并且已经有一些警告):Nawaz确实指出了用户定义的陷阱.而且我很遗憾我匆匆忙忙对"最愚蠢的问题"投了反对意见,因为似乎有很多人没有把它弄好,它为编译器优化提供了很好的讨论空间:)
答案是:
什么是
flag类型?
在flag实际上是用户定义类型的情况下.然后它取决于operator==选择的过载.当然,它们似乎很愚蠢,它们不会是对称的,但它肯定是允许的,而且我已经看到了其他的滥用行为.
如果flag是内置的,那么两者都应该采用相同的速度.
从维基百科的文章上x86,我敢打赌一Jxx对指令if语句:也许JNZ(跳转如果不是零)或某些等效.
我怀疑编译器错过了这样一个明显的优化,即使关闭优化也是如此.这是Peephole Optimization的设计类型.
编辑: Sprang再次,所以让我们添加一些程序集(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
}
Run Code Online (Sandbox Code Playgroud)
即使一个人不知道如何阅读IR,我认为这是自我解释的.
Naw*_*waz 56
您的版本没有任何区别.
我假设type标志不是用户定义的类型,而是一些内置类型.Enum是个例外!.您可以将枚举视为内置的.事实上,它的价值是内置类型之一!
如果它是用户定义的类型(除外enum),那么答案完全取决于你如何重载运算符==.请注意,您必须==通过定义两个函数来重载,每个函数对应一个函数!
小智 56
与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
Run Code Online (Sandbox Code Playgroud)
Lin*_*een 27
绝对没有区别.
通过参考消除任务/比较拼写错误,您可能会在回答该面试问题时获得积分:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
虽然这是真的,例如C编译器在前一个(flag = 0)的情况下发出警告,但在PHP,Perl或Javascript或者中没有这样的警告<insert language here>.
Jon*_*Jon 16
速度方面绝对没有区别.为什么会这样?
ds2*_*680 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;
}
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下(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
{
}
Run Code Online (Sandbox Code Playgroud)
另一方面,大多数人发现"Yoda条件"看起来很奇怪而且很烦人,特别是因为他们预防的错误类别也可以通过使用适当的编译器警告来发现.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
Run Code Online (Sandbox Code Playgroud)
正如其他人所说,没有区别.
0必须进行评估.flag必须进行评估.这个过程需要相同的时间,无论它们放在哪一侧.
正确的答案是:它们的速度都是一样的.
即使是表达式if(flag==0)也if(0==flag)有相同数量的字符!如果其中一个被编写为if(flag== 0),那么编译器将有一个额外的空间来解析,因此你有理由指出编译时间.
但由于没有这样的东西,所以绝对没有理由为什么一个人应该比其他人更快.如果有原因,那么编译器正在做一些非常非常奇怪的事情来生成代码......
好吧,我同意所有人在对OP的评论中所说的,为了运动起见:
如果编译器不够聪明(实际上你不应该使用它)或者禁用优化,x == 0可以编译为本机汇编jump if zero指令,同时0 == x可能是更通用(且代价高昂)的数值比较.
不过,我不想为一个以这些方式思考的老板工作......
哪一个快速取决于您使用的==版本.这是一个使用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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
24397 次 |
| 最近记录: |