インタビューの質問:どちらが速く実行されますif (flag==0)
かif (0==flag)
?どうして?
if(flag = 0)
は、可読性が少し犠牲になるなどのバグに対して保証されることです。
インタビューの質問:どちらが速く実行されますif (flag==0)
かif (0==flag)
?どうして?
if(flag = 0)
は、可読性が少し犠牲になるなどのバグに対して保証されることです。
回答:
正解はまだ見ていません(すでにいくつかあります)警告:Nawazはユーザー定義のトラップを指摘しました。そして、私が急いで「愚かな質問」に賛成票を投じたことを後悔しているのは、多くの人が正しく理解していないようで、コンパイラーの最適化に関する素晴らしい議論の余地があるからです:)
答えは:
flag
のタイプは何ですか?
場合にflag
、実際にユーザ定義型です。次に、どのオーバーロードoperator==
が選択されているかによって異なります。もちろん、それらが対称的ではないのは愚かに見えるかもしれませんが、それは確かに許可されており、私はすでに他の虐待を見てきました。
もし flag
が組み込みの、どちらも同じ速度になります。
Wikipediaの記事にx86
、私はのために賭ける思いJxx
のための指示if
書:おそらくJNZ
(ジャンプゼロでない場合)またはいくつかの同等のものを。
最適化がオフになっている場合でも、コンパイラーがこのような明らかな最適化を見逃しているとは思いません。これは、Peephole Optimizationが設計されているタイプの物です。
編集:再び湧き上がったので、いくつかのアセンブリを追加しましょう(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
}
IRの読み方がわからなくても自明だと思います。
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は例外です!。enumを組み込みのように扱うことができます。実際、その値は組み込み型の1つです。
その場合、それがユーザー定義型(を除くenum
)の場合、答えは完全に演算子をどのようにオーバーロードしたかに依存します==
。==
バージョンごとに1つずつ、2つの関数を定義してオーバーロードする必要があることに注意してください。
全く違いはありません。
ただし、割り当て/比較のタイプミスの排除を参照することで、そのインタビューの質問に答えることでポイントを獲得できます。
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>
。
速度的にはまったく違いはありません。なぜあるべきなのか?
x == 0
それを0 == x
使用できますが、通常の比較を使用できます。遅らせる必要があると私は言った。
virtual operator==(int)
ユーザー定義型では?
フラグがユーザー定義型の場合は違いがあります
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と比較されます。2番目のケースでは、==演算子が呼び出されます。
疑わしいときはベンチマークして真実を学んでください。
速度の点でまったく同じでなければなりません。
ただし=
、==
(等価演算子)ではなく(代入演算子)と書くと発生する可能性のあるすべてのエラーを回避するために、等値比較(いわゆる「ヨーダ条件」)で定数を左側に置く人がいることに注意してください。リテラルに割り当てるとコンパイルエラーが発生するため、この種のミスは回避されます。
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
評価する必要があります。どちらの側に配置しても、このプロセスには同じ時間がかかります。
正解は次のとおりです。どちらも同じ速度です。
でも表現if(flag==0)
とif(0==flag)
文字の同じ量を持っています!それらの1つがとして記述されているif(flag== 0)
場合、コンパイラーは解析する1つの余分なスペースを持つため、コンパイル時間を指摘することには正当な理由があります。
しかし、そのようなことはないので、他の人よりも速くあるべき理由は絶対にありません。理由がある場合、コンパイラは生成されたコードに対して非常に奇妙なことをしています...
どちらが速いかは、使用している==のバージョンによって異なります。==の2つの可能な実装を使用するスニペットは次のとおりです。x== 0または0 == xのどちらを呼び出すかによって、2つのうちの1つが選択されます。
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);
}