Welches wird schneller ausgeführt, wenn (flag == 0) oder if (0 == flag)?

111

Interviewfrage: Welches wird schneller ausgeführt, if (flag==0)oder if (0==flag)? Warum?

Vishwanath Dalvi
quelle
330
Nominiert für die dümmste Interviewfrage aller Zeiten. Und es gibt eine harte Konkurrenz.
Konrad Rudolph
119
Sie: Nennen Sie eine Situation, in der es sich möglicherweise lohnt, sich mit dem Unterschied zwischen diesen beiden zu befassen. Interviewer: Okay, du bist eingestellt.
Chris Lutz
37
Der einzige Unterschied zwischen den beiden besteht darin, dass Sie mit der späteren Konvention gegen Fehler versichert sind, if(flag = 0)zum Preis einer geringen Lesbarkeit.
Amarghosh
22
@Amarghosh: Auf Kosten der Tatsache, dass Ihr Code schwer lesbar und nicht intuitiv ist. Verwenden Sie erstere, um Ihre Compiler-Warnungen einzuschalten, Win-Win.
GManNickG
129
Einmal bekam ein Compiler-Autor dies in seinem Interview. Er flüsterte als Antwort: "Welches willst du schneller sein?".

Antworten:

236

Ich habe noch keine richtige Antwort gesehen (und es gibt bereits einige) : Nawaz hat auf die benutzerdefinierte Falle hingewiesen . Und ich bedauere meine hastige Gegenstimme zur "dümmsten Frage", denn es scheint, dass viele es nicht richtig verstanden haben und es Raum für eine nette Diskussion über die Compileroptimierung gibt :)

Die Antwort ist:

Was ist flagder Typ?

In dem Fall, in dem es sich flagtatsächlich um einen benutzerdefinierten Typ handelt. Dann kommt es darauf an, welche Überlast operator==ausgewählt ist. Natürlich kann es dumm erscheinen, dass sie nicht symmetrisch sind, aber es ist sicherlich erlaubt, und ich habe bereits andere Missbräuche gesehen.

Wenn flag es sich um ein eingebautes handelt, sollten beide die gleiche Geschwindigkeit annehmen.

Aus dem Wikipedia - Artikel auf x86, würde ich für eine Wette JxxAnweisung für die ifAussage: vielleicht eine JNZ(Sprung , wenn nicht gleich Null) oder ein Äquivalent.

Ich würde bezweifeln, dass der Compiler eine so offensichtliche Optimierung verpasst, selbst wenn die Optimierungen deaktiviert sind. Dies ist die Art von Dingen, für die Peephole Optimization entwickelt wurde.

BEARBEITEN: Wieder aufgetaucht, also fügen wir eine Baugruppe hinzu (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
}

Auch wenn man nicht weiß, wie man das IR liest, denke ich, dass es selbsterklärend ist.

Matthieu M.
quelle
4
@ Matthieu: Sie sagten, ich habe noch keine richtige Antwort gesehen .. aber meine ist richtig, ich denke: P
Nawaz
7
gut! Ihre mögliche Antwort verwandelt "die dümmste Frage" in "die trickreichsten / gemeinsten". "Lass uns ein Loch für den Kandidaten graben und sehen, ob er hineinfällt ..." :) Ich denke, wir alle gehen automatisch davon aus, dass flagdas eine ganze Zahl oder ein Boolescher Wert sein muss. OTOH, eine Variable mit dem Namen flageines benutzerdefinierten Typs zu haben, ist an sich völlig falsch, IMHO
Davka
@Nawaz: Ich habe möglicherweise den letzten Absatz Ihrer Antwort übersprungen: p
Matthieu M.
1
@Nawaz: Ich fahre nicht wirklich Rennen, ich lese normalerweise Fragen, lange nachdem sie beantwortet wurden, und die Leute neigen dazu, nur die ersten am besten bewerteten Antworten zu lesen :) Aber ich lese tatsächlich Dinge über Compiler-Optimierungen, und das kam mir wie ein Ein typischer Fall von trivialer Optimierung, also dachte ich, ich würde es den Lesern empfehlen, die sich wirklich darum kümmern ... Ich bin ziemlich überrascht, dass ich so viele positive Stimmen bekommen habe. Jetzt ist es meine am meisten gewählte Antwort, obwohl es sicherlich nicht die ist, in die ich mich am meisten bemüht habe: / Wie auch immer, ich habe meine Antwort bearbeitet und meine Aussage korrigiert :)
Matthieu M.
2
@mr_eclair: Ein integrierter Typ ist ein Typ, der (wie der Name andeutet) in der Sprache integriert ist. Das heißt, es ist auch ohne eine einzige #includeRichtlinie verfügbar . Der Einfachheit halber, es beträgt in der Regel int, char, boolund dergleichen. Alle anderen Typen sind gesagt, dass benutzerdefiniert, dh sie existieren , weil sie das Ergebnis eines Benutzers sind erklärt sie: typedef, enum, struct, class. Zum Beispiel std::stringist benutzerdefiniert, obwohl Sie es sicherlich nicht selbst definiert haben :)
Matthieu M.
56

Gleicher Code für amd64 mit 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
SK C
quelle
18
+1 für die Extrameile, um zu beweisen, dass die Compileroptimierung dieselbe ist.
k rey
56

Es wird keinen Unterschied in Ihren Versionen geben.

Ich gehe davon aus, dass das typeFlag of kein benutzerdefinierter Typ ist, sondern ein integrierter Typ. Aufzählung ist Ausnahme!. Sie können Enum so behandeln, als wäre es eingebaut. Tatsächlich handelt es sich um integrierte Werte!

Falls es sich um einen benutzerdefinierten Typ handelt (außer enum), hängt die Antwort vollständig davon ab, wie Sie den Operator überladen haben ==. Beachten Sie, dass Sie überladen müssen, ==indem Sie zwei Funktionen definieren, eine für jede Ihrer Versionen!

Nawaz
quelle
8
Dies könnte der einzig mögliche Grund sein, diese Frage zu stellen, IMHO
Davka
15
Ich wäre sehr überrascht, wenn moderne Compiler eine so offensichtliche Optimierung verpassen würden.
Pedro d'Aquino
3
Meines Wissens nach ! ist keine bitweise Operation
Xavier Combelle
8
@Nawaz: habe nicht abgelehnt, aber deine Antwort ist sachlich falsch und es ist schrecklich, dass es immer noch so viele positive Stimmen gibt. Für den Datensatz ist der Vergleich einer Ganzzahl mit 0 eine einzelne Assemblierungsanweisung , die der Negation völlig ebenbürtig ist. Wenn der Compiler etwas dumm ist, kann dies sogar schneller als die Negation sein (allerdings nicht wahrscheinlich).
Konrad Rudolph
6
@Nawaz: Es ist immer noch falsch zu sagen, dass es schneller sein kann, wird oder normalerweise wird. Wenn es einen Unterschied gibt, ist die Version "Vergleichen mit Null" schneller, da die Negation tatsächlich in zwei Operationen übersetzt wird: "Operand negieren; prüfen, ob das Ergebnis ungleich Null ist". In der Praxis optimiert der Compiler ihn natürlich so, dass er denselben Code wie die einfache Version "Vergleichen mit Null" liefert, aber die Optimierung wird auf die Negationsversion angewendet, damit sie aufholt, und nicht umgekehrt. Konrad hat recht.
Jalf
27

Es gibt absolut keinen Unterschied.

Sie können Punkte bei der Beantwortung dieser Interviewfrage sammeln, indem Sie sich auf die Beseitigung von Zuweisungs- / Vergleichstipps beziehen:

if (flag = 0)  // typo here
   {
   // code never executes
   }

if (0 = flag) // typo and syntactic error -> compiler complains
   {
   // ...
   }

Während es wahr ist, dass zB ein C-Compiler im Fall des ersteren ( flag = 0) warnt , gibt es keine solchen Warnungen in PHP, Perl oder Javascript oder <insert language here>.

Linus Kleen
quelle
@ Matieu Huh. Ich muss den Beitrag auf Meta verpasst haben , der den "richtigen" Klammerstil beschreibt.
Linus Kleen
7
Ich habe überhaupt nicht abgestimmt, aber für das, was es wert ist: Warum ist es so wichtig, dass sich die Leute erklären, wann immer sie abstimmen? Die Stimmen sind von Natur aus anonym. Ich bin völlig gegen die Idee, dass Downvoter immer kommentieren sollten, weil ich persönlich nie als Downvoter angenommen werden möchte, nur weil ich einen Kommentar hinterlassen habe, der auf ein Problem hinweist. Vielleicht dachte der Downvoter, der Großteil der Antwort sei für die Geschwindigkeitsfrage irrelevant? Vielleicht dachte er, dass es einen Codierungsstil ermutigte, den er nicht gut fand? Vielleicht war er ein Schwanz und wollte, dass seine eigene Antwort die höchste Bewertung hat?
David Hedlund
3
Die Menschen sollten unabhängig vom Grund frei wählen können. In Bezug auf das Ansehen ist dies fast immer eine gute Sache, da es andere Leute oft dazu bringt, sich zu verbessern, um der unverdienten Abwertung entgegenzuwirken, obwohl eine einzige Aufwertung tatsächlich fünf unverdiente Abstimmungen aufheben würde.
David Hedlund
26
@ David: Downvoters sollten sich erklären, weil es auf dieser Seite nicht um geheime Beliebtheitswahlen, anonyme Abstimmungen oder ähnliches geht. Auf dieser Seite geht es ums Lernen. Wenn jemand sagt, dass eine Antwort durch Downvoting falsch ist, ist der Downvoter mit seinem Wissen egoistisch, wenn er nicht erklärt, warum. Sie sind bereit, alle Ehre zu machen, wenn sie Recht haben, aber nicht bereit, Wissen zu teilen, wenn andere Unrecht haben.
John Dibling
1
Ich denke wirklich, dass Matthieu das nur als Witz gedacht hat, um das Problem des Stützstils aus dem Weg zu räumen. Es würde mich überraschen zu sehen, dass jemand seine Stimmen abhängig von solchen Themen abgibt. Allerdings verwendet nicht jeder die Stimmen genauso. Ich konnte die Gründe für das Downvoting erkennen, da der Beitrag einen Codierungsstil zu befürworten scheint, den der Wähler möglicherweise ablehnt (beachten Sie den Unterschied zwischen der Befürwortung eines Codierungsstils - "Wenn Sie Ihren Code so schreiben, wird beim Erstellen ein Compilerfehler angezeigt dieser Tippfehler "- und einfach mit einem Codierungsstil, wie z. B. geschweiften Klammern) In diesem ...
David Hedlund
16

In Bezug auf die Geschwindigkeit wird es absolut keinen Unterschied geben. Warum sollte es geben?

Jon
quelle
7
wenn der Compiler vollständig verzögert war. Das ist der einzige Grund.
JeremyP
@JeremyP: Ich kann mir keinen Unterschied vorstellen, selbst wenn der Compiler verzögert wäre. Der Compiler-Autor müsste dies absichtlich tun, soweit ich das beurteilen kann.
Jon
2
Angenommen, der Prozessor verfügt über einen Befehl "Test if 0", der x == 0möglicherweise verwendet wird, aber 0 == xmöglicherweise einen normalen Vergleich verwendet. Ich habe gesagt, es müsste verzögert werden.
JeremyP
8
Wenn Flag ein benutzerdefinierter Typ mit einer asymmetrischen Überladung von Operator == () ist
OrangeDog
Weil wir vielleicht haben virtual operator==(int)in einem benutzerdefinierten Typ?
Lorro
12

Nun, es gibt einen Unterschied, wenn flag ein benutzerdefinierter Typ ist

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;
    }
}

Im ersten Fall (0 == s) wird der Konvertierungsoperator aufgerufen und das zurückgegebene Ergebnis mit 0 verglichen. Im zweiten Fall wird der Operator == aufgerufen.

ds27680
quelle
3
+1 für die Erwähnung, dass ein Konvertierungsoperator genauso relevant sein könnte wie ein Operator ==.
Tony Delroy
11

Wenn Sie Zweifel haben, messen Sie es und erfahren Sie die Wahrheit.

Elzo Valugi
quelle
2
Was ist falsch am Benchmarking? Manchmal sagt Ihnen die Praxis mehr als die Theorie
Elzo Valugi
1
Das ist die Antwort, nach der ich gesucht habe, als ich anfing, diesen Thread zu lesen. Es scheint, dass die Theorie ansprechender ist als die Praxis, wenn man die Antworten und Gegenstimmen betrachtet :)
Samuel Rivas
Wie konnte er beim Interview einen Benchmark erstellen? Außerdem denke ich, dass der Interviewer nicht einmal weiß, was Benchmarking bedeutet, also hätte er beleidigt sein können.
IAdapter
Die richtige Antwort auf die Frage (IMO) lautet: "Das hängt ziemlich stark vom Compiler und dem Rest des Programms ab. Ich würde einen Benchmark schreiben und ihn in 5 Minuten testen"
Samuel Rivas
7

Sie sollten in Bezug auf die Geschwindigkeit genau gleich sein.

Beachten Sie jedoch, dass einige Leute die Konstante in Gleichheitsvergleichen links verwenden (die sogenannten "Yoda-Bedingungen"), um alle Fehler zu vermeiden, die auftreten können, wenn Sie =(Zuweisungsoperator) anstelle von ==(Gleichheitsvergleichsoperator) schreiben . Da das Zuweisen zu einem Literal einen Kompilierungsfehler auslöst, wird diese Art von Fehler vermieden.

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
{

}

Auf der anderen Seite finden die meisten Leute "Yoda-Bedingungen" seltsam und nervig, zumal die Klasse der Fehler, die sie verhindern, auch durch die Verwendung geeigneter Compiler-Warnungen erkannt werden kann.

if(flag=0) // <--- warning: assignment in conditional expression
{

}
Matteo Italia
quelle
Danke fürs Echo. Beachten Sie jedoch, dass PHP beispielsweise bei Zuweisungen in Bedingungen nicht warnt.
Linus Kleen
5

Wie andere gesagt haben, gibt es keinen Unterschied.

0muss bewertet werden. flagmuss bewertet werden. Dieser Vorgang dauert genauso lange, egal auf welcher Seite sie platziert sind.

Die richtige Antwort wäre: Sie sind beide gleich schnell.

Sogar die Ausdrücke if(flag==0)und if(0==flag)haben die gleiche Anzahl von Zeichen! Wenn einer von ihnen als geschrieben if(flag== 0)wäre, hätte der Compiler einen zusätzlichen Speicherplatz zum Parsen, sodass Sie einen berechtigten Grund hätten, auf die Kompilierungszeit hinzuweisen.

Aber da es so etwas nicht gibt, gibt es absolut keinen Grund, warum einer schneller sein sollte als der andere. Wenn es einen Grund gibt, macht der Compiler einige sehr, sehr seltsame Dinge mit dem generierten Code ...

Darioo
quelle
5

Welches schnell ist, hängt davon ab, welche Version von == Sie verwenden. Hier ist ein Ausschnitt, der zwei mögliche Implementierungen von == verwendet. Je nachdem, ob Sie x == 0 oder 0 == x aufrufen, wird eine der beiden ausgewählt.

Wenn Sie nur einen POD verwenden, sollte dies in Bezug auf die Geschwindigkeit keine Rolle spielen.

#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);
}
Fanatic23
quelle
5

Nun, ich stimme allen Aussagen in den Kommentaren zum OP voll und ganz zu, um der Übung willen:

Wenn der Compiler nicht klug genug ist (in der Tat sollten Sie ihn nicht verwenden) oder die Optimierung deaktiviert ist, x == 0könnte er jump if zerowährenddessen zu einer nativen Assembly- Anweisung kompiliert werden0 == x ein allgemeinerer (und kostspieligerer) Vergleich numerischer Werte möglich ist.

Trotzdem würde ich nicht gerne für einen Chef arbeiten, der so denkt ...

Davka
quelle
4

Sicherlich kein Unterschied in Bezug auf die Ausführungsgeschwindigkeit. Der Zustand muss in beiden Fällen gleich bewertet werden.

Sachin Shanbhag
quelle
3

Ich denke, die beste Antwort ist "In welcher Sprache ist dieses Beispiel?"

Die Frage hat die Sprache nicht angegeben und ist sowohl mit 'C' als auch mit 'C ++' gekennzeichnet. Eine genaue Antwort benötigt mehr Informationen.

Es ist eine miese Programmierfrage, aber es könnte eine gute Frage in der verschlagenen Abteilung "Geben wir dem Befragten genug Seil, um sich entweder aufzuhängen oder eine Baumschaukel zu bauen" sein. Das Problem bei solchen Fragen ist, dass sie normalerweise von Interviewer zu Interviewer aufgeschrieben und weitergegeben werden, bis sie an Leute gelangen, die sie nicht wirklich aus allen Blickwinkeln verstehen.

Marsh Ray
quelle
3

Erstellen Sie zwei einfache Programme auf die vorgeschlagenen Arten.

Bauen Sie die Codes zusammen. Schauen Sie sich die Versammlung an und Sie können beurteilen, aber ich bezweifle, dass es einen Unterschied gibt!

Die Interviews werden niedriger als je zuvor.

Syntax-Fehler
quelle
2

Abgesehen davon (ich denke tatsächlich, dass jeder anständige Compiler diese Frage in Frage stellen wird, da sie optimiert wird) verhindert die Verwendung von 0 == flag over flag == 0 den Tippfehler, bei dem Sie eines der = vergessen (dh wenn Sie versehentlich tippen) flag = 0 wird kompiliert, aber 0 = flag wird nicht), was ich für einen Fehler halte, den jeder an dem einen oder anderen Punkt gemacht hat ...

Kindread
quelle
0

Wenn es überhaupt einen Unterschied gab, was hält den Compiler davon ab, den schnelleren einmal zu wählen? Logischerweise kann es keinen Unterschied geben. Wahrscheinlich erwartet der Interviewer dies. Es ist eigentlich eine brillante Frage.

balki
quelle