Interview question: Which one 开发者_如何学编程will execute faster, if (flag==0)
or if (0==flag)
? Why?
I haven't seen any correct answer yet (and there are already some) caveat: Nawaz did point out the user-defined trap. And I regret my hastily cast upvote on "stupidest question" because it seems that many did not get it right and it gives room for a nice discussion on compiler optimization :)
The answer is:
What is
flag
's type?
In the case where flag
actually is a user-defined type. Then it depends on which overload of operator==
is selected. Of course it can seem stupid that they would not be symmetric, but it's certainly allowed, and I have seen other abuses already.
If flag
is a built-in, then both should take the same speed.
From the Wikipedia article on x86
, I'd bet for a Jxx
instruction for the if
statement: perhaps a JNZ
(Jump if Not Zero) or some equivalent.
I'd doubt the compiler misses such an obvious optimization, even with optimizations turned off. This is the type of things for which Peephole Optimization is designed for.
EDIT: Sprang up again, so let's add some assembly (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
}
Even if one does not know how to read the IR, I think it is self explanatory.
Same code for amd64 with 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
There will be no difference in your versions.
I'm assuming that the type
of flag is not user-defined type, rather it's some built-in type. Enum is exception!. You can treat enum as if it's built-in. In fact, it' values are one of built-in types!
In case, if it's user-defined type (except enum
), then the answer entirely depends on how you've overloaded the operator ==
. Note that you've to overload ==
by defining two functions, one for each of your versions!
There is absolutely no difference.
You might gain points in answering that interview question by referring to the elimination of assignment/comparison typos, though:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
While it's true, that e.g. a C-compiler does warn in case of the former (flag = 0
), there are no such warnings in PHP, Perl or Javascript or <insert language here>
.
There will be absolutely no difference speed-wise. Why should there be?
Well there is a difference when flag is a user defined type
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;
}
}
In the first case (0==s) the conversion operator is called and then the returned result is compared to 0. In the second case the == operator is called.
When in doubt benchmark it and learn the truth.
They should be exactly the same in terms of speed.
Notice however that some people use to put the constant on the left in equality comparisons (the so-called "Yoda conditionals") to avoid all the errors that may arise if you write =
(assignment operator) instead of ==
(equality comparison operator); since assigning to a literal triggers a compilation error, this kind of mistake is avoided.
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
{
}
On the other hand, most people find "Yoda conditionals" weird-looking and annoying, especially since the class of errors they prevent can be spotted also by using adequate compiler warnings.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
As others have said, there is no difference.
0
has to be evaluated. flag
has to be evaluated. This process takes the same time, no matter which side they're placed.
The right answer would be: they're both the same speed.
Even the expressions if(flag==0)
and if(0==flag)
have the same amount of characters! If one of them was written as if(flag== 0)
, then the compiler would have one extra space to parse, so you would have a legitimate reason at pointing out compile time.
But since there is no such thing, there is absolutely no reason why one should be faster than other. If there is a reason, then the compiler is doing some very, very strange things to generated code...
Which one's fast depends on which version of == you are using. Here's a snippet that uses 2 possible implementations of ==, and depending on whether you choose to call x == 0 or 0 == x one of the 2 is selected.
If you are just using a POD this really shouldn't matter when it comes to speed.
#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);
}
Well, I am agreeing completely with all said in the comments to the OP, for the exercise sake:
If the compiler is not clever enough (indeed you should not use it) or the optimization is disabled, x == 0
could compile to a native assembly jump if zero
instruction, while 0 == x
could be a more generic (and costly) comparison of numeric values.
Still, I wouldn't like to work for a boss who thinks in these terms...
Surely no difference in terms of execution speeds. The condition needs to be evaluated in both cases in the same way.
I think the best answer is "what language is this example in"?
The question did not specify the language and it's tagged both 'C' and 'C++'. A precise answer needs more information.
It's a lousy programming question, but it could be a good in the devious "let's give the interviewee enough rope to either hang himself or build a tree swing" department. The problem with those kinds of questions is they usually get written down and handed down from interviewer to interviewer until it gets to people who don't really understand it from all the angles.
Build two simple programs using the suggested ways.
Assemble the codes. Look at the assembly and you can judge, but I doubt there is a difference!
Interviews are getting lower than ever.
Just as an aside ( I actually think any decent compiler will make this question moot, since it will optimise it ) using 0 == flag over flag == 0 does prevent the typo where you forget one of the = ( ie if you accidently type flag = 0 it will compile, but 0 = flag will not ), which I think is a mistake everyone has made at one point or another...
If at all there was a difference, what stops compiler to choose the faster once? So logically, there can't be any difference. Probably this is what the interviewer expects. It is actually a brilliant question.
精彩评论