Pytanie do wywiadu: Który z nich zadziała szybciej, if (flag==0)czy if (0==flag)? Czemu?
if(flag = 0)za cenę niewielkiej czytelności.
Pytanie do wywiadu: Który z nich zadziała szybciej, if (flag==0)czy if (0==flag)? Czemu?
if(flag = 0)za cenę niewielkiej czytelności.
Odpowiedzi:
Nie widziałem jeszcze żadnej poprawnej odpowiedzi (a jest już kilka) zastrzeżenie: Nawaz zwrócił uwagę na pułapkę zdefiniowaną przez użytkownika . I żałuję, że pośpiesznie oddałem głos za "najgłupsze pytanie", ponieważ wydaje się, że wielu nie odpowiedziało dobrze i daje to miejsce na miłą dyskusję na temat optymalizacji kompilatora :)
Odpowiedź to:
Jaki jest
flagtyp?
W przypadku, gdy flagfaktycznie jest to typ zdefiniowany przez użytkownika. To zależy od tego, które przeciążenie operator==jest wybrane. Oczywiście może wydawać się głupie, że nie byłyby symetryczne, ale z pewnością jest to dozwolone, a widziałem już inne nadużycia.
Jeśli flagjest wbudowany, oba powinny mieć tę samą prędkość.
Z Wikipedii sprawie x86, założę się o Jxxinstrukcje do ifstwierdzenia: być może JNZ(Przełącz jeśli nie zero) lub jakiś odpowiednik.
Wątpię, by kompilator pominął tak oczywistą optymalizację, nawet przy wyłączonych optymalizacjach. To jest rodzaj rzeczy, dla których jest przeznaczona Optymalizacja Peephole .
EDYCJA: Znowu wyskoczył, więc dodajmy trochę assemblacji (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
}
Nawet jeśli nie umie się czytać IR, myślę, że jest to oczywiste.
flagmusi to być liczba całkowita lub wartość logiczna. OTOH, posiadanie zmiennej o nazwie flagtypu zdefiniowanego przez użytkownika jest dość złe samo w sobie, IMHO
#includedyrektywy. Dla uproszczenia, to zwykle wynosi int, char, booli tym podobne. Wszystkie pozostałe rodzaje Mówi się, że zdefiniowane przez użytkownika, to one istnieją, ponieważ są one wynikiem jakiegoś użytkownik je uznającej: typedef, enum, struct, class. Na przykład, std::stringjest zdefiniowany przez użytkownika, nawet jeśli na pewno nie zdefiniowałeś go sam :)
Ten sam kod dla amd64 z 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
W twoich wersjach nie będzie różnicy.
Zakładam, że typeflaga of nie jest typem zdefiniowanym przez użytkownika, a raczej typem wbudowanym. Enum jest wyjątkiem! . Wyliczenie można traktować tak, jakby było wbudowane. W rzeczywistości to wartości są jednym z wbudowanych typów!
W przypadku, jeśli jest to typ zdefiniowany przez użytkownika (z wyjątkiem enum), odpowiedź całkowicie zależy od tego, jak przeciążono operator ==. Zauważ, że musisz przeciążać ==, definiując dwie funkcje, po jednej dla każdej wersji!
Nie ma absolutnie żadnej różnicy.
Możesz zyskać punkty, odpowiadając na to pytanie podczas rozmowy kwalifikacyjnej, odwołując się do eliminacji literówek przy przypisaniu / porównaniach, chociaż:
if (flag = 0) // typo here
{
// code never executes
}
if (0 = flag) // typo and syntactic error -> compiler complains
{
// ...
}
Chociaż prawdą jest, że np. Kompilator C ostrzega w przypadku poprzedniej ( flag = 0), nie ma takich ostrzeżeń w PHP, Perl, Javascript lub <insert language here>.
Nie będzie żadnej różnicy pod względem prędkości. Dlaczego miałoby być?
x == 0może jej użyć, ale 0 == xmoże użyć normalnego porównania. Powiedziałem, że to będzie musiało być opóźnione.
virtual operator==(int)typu zdefiniowanego przez użytkownika?
Cóż, jest różnica, gdy flaga jest typem zdefiniowanym przez użytkownika
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;
}
}
W pierwszym przypadku (0 == s) wywoływany jest operator konwersji, a następnie zwracany wynik jest porównywany z 0. W drugim przypadku wywoływany jest operator ==.
W razie wątpliwości sprawdź to i poznaj prawdę.
Powinny być dokładnie takie same pod względem szybkości.
Zauważ jednak, że niektórzy ludzie umieszczają stałą po lewej stronie w porównaniach równości (tak zwane „warunkowe Yoda”), aby uniknąć wszystkich błędów, które mogą się pojawić, jeśli napiszesz =(operator przypisania) zamiast ==(operator porównania równości); ponieważ przypisanie do literału wyzwala błąd kompilacji, można uniknąć tego rodzaju błędów.
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
{
}
Z drugiej strony, większość ludzi uważa, że „warunkowe Yoda” wyglądają dziwnie i denerwują, zwłaszcza, że klasy błędów, którym zapobiegają, można wykryć również przy użyciu odpowiednich ostrzeżeń kompilatora.
if(flag=0) // <--- warning: assignment in conditional expression
{
}
Jak powiedzieli inni, nie ma różnicy.
0podlega ocenie. flagpodlega ocenie. Ten proces zajmuje tyle samo czasu, bez względu na to, po której stronie się znajdują.
Prawidłowa odpowiedź brzmiałaby: obie mają taką samą prędkość.
Nawet wyrażenia if(flag==0)i if(0==flag)mają taką samą liczbę znaków! Jeśli jeden z nich if(flag== 0)zostałby zapisany jako , kompilator miałby jedną dodatkową przestrzeń do przeanalizowania, więc miałbyś uzasadniony powód, aby wskazać czas kompilacji.
Ale ponieważ czegoś takiego nie ma, nie ma absolutnie żadnego powodu, dla którego jeden miałby być szybszy od drugiego. Jeśli istnieje powód, kompilator robi bardzo, bardzo dziwne rzeczy z wygenerowanym kodem ...
Który z nich jest szybki, zależy od używanej wersji ==. Oto fragment, który wykorzystuje 2 możliwe implementacje == i w zależności od tego, czy zdecydujesz się wywołać x == 0, czy 0 == x zostanie wybrana jedna z 2.
Jeśli używasz tylko POD, to naprawdę nie powinno mieć znaczenia, jeśli chodzi o szybkość.
#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);
}
Cóż, całkowicie zgadzam się ze wszystkim, co zostało powiedziane w komentarzach do PO, na potrzeby ćwiczenia:
Jeśli kompilator nie jest wystarczająco sprytny (rzeczywiście nie powinieneś go używać) lub optymalizacja jest wyłączona, x == 0może skompilować się do natywnej jump if zeroinstrukcji asemblera , podczas gdy 0 == xmoże być bardziej ogólnym (i kosztownym) porównaniem wartości liczbowych.
Mimo wszystko nie chciałbym pracować dla szefa, który myśli w ten sposób ...
Z pewnością nie ma różnicy w szybkości wykonywania. Warunek należy ocenić w obu przypadkach w ten sam sposób.
Myślę, że najlepszą odpowiedzią jest „w jakim języku jest ten przykład”?
Pytanie nie określało języka i zostało oznaczone jako „C” i „C ++”. Dokładna odpowiedź wymaga więcej informacji.
To kiepskie pytanie programistyczne, ale może być dobre w dziale „dajmy rozmówcy wystarczająco dużo liny, żeby się powiesić lub zbudować huśtawkę na drzewo”. Problem z tego rodzaju pytaniami polega na tym, że zwykle są one zapisywane i przekazywane od osoby przeprowadzającej rozmowę do osoby prowadzącej rozmowę, aż trafiają do osób, które nie rozumieją ich ze wszystkich stron.
Zbuduj dwa proste programy, korzystając z sugerowanych sposobów.
Zbierz kody. Spójrz na zgromadzenie i możesz ocenić, ale wątpię, czy jest jakaś różnica!
Wywiady są coraz niższe niż kiedykolwiek.
Tak na marginesie (myślę, że każdy przyzwoity kompilator sprawi, że to pytanie będzie dyskusyjne, ponieważ zoptymalizuje je) użycie 0 == flag over flag == 0 zapobiega literówce, w której zapomnisz jednego z = (tj. Jeśli przypadkowo wpiszesz flag = 0 skompiluje się, ale 0 = flaga nie), co moim zdaniem jest błędem, który wszyscy popełnili w takim czy innym momencie ...