Mülakat soru: Bir daha hızlı yürütmek, olur if (flag==0)ya if (0==flag)? Neden?
if(flag = 0)biraz okunabilirlik fiyatıyla böceklere karşı sigortalı olmanızdır .
Mülakat soru: Bir daha hızlı yürütmek, olur if (flag==0)ya if (0==flag)? Neden?
if(flag = 0)biraz okunabilirlik fiyatıyla böceklere karşı sigortalı olmanızdır .
Yanıtlar:
Henüz doğru bir cevap görmedim (ve zaten bir miktar var) uyarı: Nawaz kullanıcı tanımlı tuzağa işaret etti . Ve "en aptal soru" üzerine aceleyle verdiğim oy için pişmanlık duyuyorum çünkü çoğu kişi bunu doğru anlamadı ve derleyici optimizasyonu hakkında güzel bir tartışma için yer veriyor gibi görünüyor :)
Cevap:
Nedir
flagbireyin tipi?
flagGerçekte kullanıcı tanımlı bir tür olduğu durumda . Daha sonra hangi aşırı yükün operator==seçildiğine bağlıdır . Elbette simetrik olmayacakları aptalca görünebilir, ancak kesinlikle izin verilir ve başka suistimaller de gördüm.
Yerleşik flagise, her ikisi de aynı hızı almalıdır.
Gönderen Wikipedia makalesinin üzerinde x86, bir için bahse girerim Jxxiçin talimat ififadesi: belki JNZ(Jump Değil Zero ise) ya da bazı eşdeğeri.
Optimizasyonlar kapalıyken bile derleyicinin bu kadar bariz bir optimizasyonu kaçırdığından şüpheliyim. Bu, Gözetleme Deliği Optimizasyonunun tasarlandığı türden şeylerdir .
DÜZENLEME: Yeniden ortaya çıktı, bu yüzden biraz montaj ekleyelim (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'nin nasıl okunacağını bilmeseniz bile, bunun kendi kendini açıklayıcı olduğunu düşünüyorum.
flagbunun tamsayı veya boole olması gerektiğini varsayıyoruz . flagKullanıcı tanımlı türde bir değişkene sahip olan OTOH kendi başına oldukça yanlış, IMHO
#includeyönerge olmadan da kullanılabilir . Basitlik uğruna, genellikle tutarındaki int, char, boolve benzeri. Diğer tüm türleri onları beyan bazı kullanıcı sonucudur çünkü onların var olduğunu, kullanıcı tanımlı olduğu söylenen: typedef, enum, struct, class. Örneğin, std::stringkesinlikle kendiniz tanımlamamış olsanız bile kullanıcı tanımlıdır :)
GCC 4.1.2 ile amd64 için aynı kod:
.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
Sürümlerinizde hiçbir fark olmayacak.
typeBayrağının kullanıcı tanımlı bir tür olmadığını, bunun yerine yerleşik bir tür olduğunu varsayıyorum . Enum istisnadır! . Numaralamayı yerleşikmiş gibi ele alabilirsiniz. Aslında, değerleri yerleşik türlerden biridir!
Kullanıcı tanımlı tür ise (hariç enum), yanıt tamamen operatörü nasıl aşırı yüklediğinize bağlıdır ==. ==Sürümlerinizin her biri için bir tane olmak üzere iki işlev tanımlayarak aşırı yüklemeniz gerektiğini unutmayın !
Kesinlikle hiçbir fark yok.
Atama / karşılaştırma yazım hatalarının ortadan kaldırılmasına atıfta bulunarak bu röportaj sorusunu yanıtlarken puan kazanabilirsiniz, ancak:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
Örneğin bir C-derleyicisinin eski ( flag = 0) durumunda uyarı verdiği doğru olsa da PHP, Perl veya Javascript veya <insert language here>.
Hız açısından kesinlikle bir fark olmayacak. Neden olmalı?
x == 0onu kullanabilir ancak 0 == xnormal bir karşılaştırma kullanabilir. Gecikmesi gerektiğini söylemiştim.
virtual operator==(int)bir kullanıcı tanımlı tür?
Flag, kullanıcı tanımlı bir tür olduğunda bir fark vardır
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;
}
}
İlk durumda (0 == s) dönüştürme operatörü çağrılır ve sonra döndürülen sonuç 0 ile karşılaştırılır. İkinci durumda == operatörü çağrılır.
Şüpheye düştüğünüzde, onu kıyaslayın ve gerçeği öğrenin.
Hız açısından tam olarak aynı olmalılar.
Bununla birlikte, bazı kişilerin (eşitlik karşılaştırma operatörü) =yerine (atama operatörü) yazarsanız ortaya çıkabilecek tüm hataları önlemek için eşitlik karşılaştırmalarında ("Yoda koşullu" olarak adlandırılan) sabiti sola koymak için kullandığına dikkat edin ==; Birebir atama, bir derleme hatasını tetiklediğinden, bu tür bir hatadan kaçınılır.
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
{
}
Öte yandan, çoğu insan "Yoda koşullarını" tuhaf ve sinir bozucu buluyor, özellikle de önledikleri hata sınıfı yeterli derleyici uyarıları kullanılarak da tespit edilebildiği için.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
Başkalarının dediği gibi, hiçbir fark yok.
0değerlendirilmesi gerekiyor. flagdeğerlendirilmesi gerekiyor. Bu işlem, hangi tarafa yerleştirilirse yerleştirilsin aynı süreyi alır.
Doğru cevap şu olacaktır: ikisi de aynı hızda.
Hatta ifadeler if(flag==0)ve if(0==flag)aynı sayıda karaktere sahip! Bunlardan biri olarak yazıldıysa if(flag== 0), derleyicinin ayrıştırmak için fazladan bir boşluğu olur, bu nedenle derleme zamanını belirtmek için geçerli bir nedeniniz olur.
Ancak böyle bir şey olmadığı için, birinin diğerinden daha hızlı olması için kesinlikle hiçbir neden yoktur. Bir sebep varsa, derleyici kod oluşturmak için çok ama çok garip şeyler yapıyor demektir ...
Hangisinin hızlı olduğu == sürümünün hangi sürümünü kullandığınıza bağlıdır. Burada, 2 olası == uygulamasını kullanan ve x == 0 veya 0 == x aramayı seçip seçmediğinize bağlı olarak 2'den biri seçili olan bir pasaj.
Sadece bir POD kullanıyorsanız, hız söz konusu olduğunda bu gerçekten önemli olmamalı.
#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);
}
Eh, alıştırma uğruna, OP'ye yapılan yorumlarda söylenenlerin hepsine tamamen katılıyorum:
Derleyici yeterince akıllı değilse (aslında onu kullanmamalısınız) veya optimizasyon devre dışı bırakılmışsa, sayısal değerlerin daha genel (ve maliyetli) bir karşılaştırması olurken x == 0yerel bir montaj jump if zerotalimatına derlenebilir 0 == x.
Yine de bu şekilde düşünen bir patron için çalışmak istemem ...
Uygulama hızları açısından kesinlikle bir fark yok. Her iki durumda da durumun aynı şekilde değerlendirilmesi gerekir.
Bence en iyi yanıt "bu örnek hangi dilde"?
Soru dili belirtmedi ve hem 'C' hem de 'C ++' olarak etiketlendi. Kesin bir cevap daha fazla bilgiye ihtiyaç duyar.
Bu çok kötü bir programlama sorusu, ancak "görüşülen kişiye kendini asması ya da bir ağaç salıncağı inşa etmesi için yeterince ip verelim" bölümünde iyi olabilir. Bu tür sorularla ilgili sorun, genellikle yazılmaları ve görüşmeciden görüşmeciye, tüm açılardan gerçekten anlamayan insanlara ulaşana kadar aktarılmasıdır.
Önerilen yolları kullanarak iki basit program oluşturun.
Kodları birleştirin. Meclise bakın ve yargılayabilirsiniz, ancak bir fark olduğundan şüpheliyim!
Görüşmeler her zamankinden daha düşük.
Bir kenara olarak (aslında herhangi bir iyi derleyicinin bu soruyu tartışmalı hale getireceğini düşünüyorum, çünkü optimize edeceğini düşünüyorum) 0 == flag over flag == 0 kullanmak = 'den birini unuttuğunuz yazım hatasını engeller (yani yanlışlıkla yazarsanız bayrak = 0 derlenecek, ancak 0 = bayrak olmayacak), ki bence herkesin bir noktada yaptığı bir hata ...