Ternärer Operator ?: Vs wenn ... sonst

79

Ist der Operator ?: In C ++ schneller als if () ... else-Anweisungen? Gibt es Unterschiede zwischen ihnen im kompilierten Code?

Xirdus
quelle
Schwierige Frage, da dies auch von der Optimierungseinstellung des Compilers abhängen würde.
extraneon
3
Das hängt sicherlich davon ab, was Sie in den Filialen tun. Der bedingte Operator lässt nur Ausdrücke zu, während ifAnweisungen zulässig sind.
Gumbo
3
verwandt: ternär oder nicht ternär?
Nick Dandoulakis
8
Ein Typ hat zufällig beschlossen, meine drei Jahre alte Frage zu bearbeiten, die Frage so umzuschreiben, dass sie sich völlig anders anhört als ich, und einen völlig unnötigen Code hinzuzufügen, der das ganze Problem sinnlos macht, da beide Beispiele dank ständiger Faltung auf ein einfaches "Ergebnis reduziert werden = 5 ". Zurücksetzen.
Xirdus
Baugruppenversion cmov vs jmp stackoverflow.com/questions/14131096/…
Ciro Santilli 19 冠状 病 六四 事件 19

Antworten:

87

Hängt von Ihrem Compiler ab, aber bei jedem modernen Compiler gibt es im Allgemeinen keinen Unterschied. Darüber sollten Sie sich keine Sorgen machen. Konzentrieren Sie sich auf die Wartbarkeit Ihres Codes.

Ptomato
quelle
1
+1 Für viele Anwendungen ist der Perf-Unterschied selbst bei einem echten Dump-Compiler nicht zu berücksichtigen.
3
In Bezug auf die Wartbarkeit von Code würde ich es vorziehen, wenn ... sonst. Zumindest für mich ist es leichter zu lesen.
Exa
2
@Exa: Hängt vom Kontext ab. Der ternäre Operator ist häufig besser, wenn Sie ein Objekt initialisieren.
Nemanja Trifunovic
@Nemanja: Deshalb habe ich "Zumindest für mich" gesagt. Ich bezog mich nur auf die Lesbarkeit von Code :)
Exa
1
@ Kotlinski, ich sage nicht, dass eine Bedingung weniger wartbar ist als ein Wenn. Sie sind beide unter bestimmten, unterschiedlichen Umständen klarer, wie in den Antworten der oben verlinkten ternären oder nicht ternären Frage beschrieben.
Ptomato
107

Es ist nicht schneller. Es gibt einen Unterschied, wenn Sie eine konstante Variable abhängig von einem Ausdruck initialisieren können:

const int x = (a<b) ? b : a;

Mit dem kann man nicht dasselbe machen if-else.

Kirill V. Lyadvinsky
quelle
20
@Developer Art: Was mit einer constVariablen nicht möglich ist.
Job
1
Sie können eine Variable ohne Konstante erstellen, sie im if / else zuweisen, dann eine neue Konstantenvariable erstellen und mit der Nichtkonstante erstellen. Eher verschwenderisch, aber alles andere als unmöglich.
Welpe
1
Ich sagte, dass es verschwenderisch sei. Sie haben nur ein Beispiel dafür gegeben, wie es eine Verschwendung ist. Aber es ist absolut nicht unmöglich.
Welpe
7
Was ist mit dem guten alten max? const int x = max(a,b);funktioniert gut.
Bobobobo
3
@ Bobobobo ha! Als ich Ihren Kommentar las, dachte ich, der Befehl, den Sie vorschlagen, war max ? const int x = max(a,b);und dachte whoa! Was zum Teufel ist das! dann las ich es noch einmal und bemerkte, dass das Fragezeichen kein Monospace war! Angesichts des Themas denke ich, dass ich berechtigt war, das zu denken? war Teil des Befehls! :)
Dewd
43

Ich habe gesehen, wie GCC den bedingten Operator in cmovAnweisungen (bedingte Verschiebung) umwandelte, während ifAnweisungen in Zweige umgewandelt wurden, was in unserem Fall bedeutete, dass der Code bei Verwendung des bedingten Operators schneller war. Aber das war vor ein paar Jahren und höchstwahrscheinlich würden beide heute mit demselben Code kompiliert werden.

Es gibt keine Garantie dafür, dass sie mit demselben Code kompiliert werden. Wenn Sie die Leistung benötigen, messen Sie wie immer . Und wenn Sie gemessen und herausgefunden haben, dass 1. Ihr Code zu langsam ist und 2. dieser bestimmte Codeabschnitt der Schuldige ist, studieren Sie den vom Compiler generierten Assembler-Code und überprüfen Sie selbst, was passiert.

Vertrauen Sie nicht goldenen Regeln wie "Der Compiler generiert immer effizienteren Code, wenn ich den bedingten Operator verwende".

jalf
quelle
2
+1. Als ich mit GCC für PS3 entwickelte, war es nützlich, Bedingungen anstelle von "if" zu verwenden, um Verzweigungen zu vermeiden.
Johan Kotlinski
Ist das spezifisch für die Sprache c? Der Standard von c ++ sagt, Only one of the second and third expressions is evaluated. Every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression.was den Compiler anscheinend daran hindert, cmoveAnweisungen zu generieren .
Zoujyjs
2
@zoujyjs nein, C hat die gleiche Regel. Nach der Als-ob-Regel kann der Compiler jedoch betrügen, solange das Endergebnis korrekt ist. Solange keine Nebenwirkungen auftreten, kann der Compiler diese Optimierung vornehmen.
Jalf
Wie implementiere ich sonst mit cmov? Ein Mov auf Wert 1 + ein cmov auf Wert 2?
Ciro Santilli 法轮功 冠状 病 六四 事件 19
1
HINWEIS: Dieser Rat ist veraltet (cira 2010). Ich konnte ihn auf gcc 4.4 oder höher nicht reproduzieren.
ACyclic
15

Sie sind die gleichen, jedoch kann der ternäre Operator an Orten verwendet werden, an denen es schwierig ist, ein if / else zu verwenden:

printf("Total: %d item%s", cnt, cnt != 1 ? "s" : "");

Wenn Sie diese Anweisung mit einem if / else ausführen, wird ein ganz anderer kompilierter Code generiert.


Update nach 8 Jahren ...

Eigentlich denke ich, das wäre besser:

printf(cnt == 1 ? "Total: %d item" : "Total: %d items", cnt);

(Eigentlich bin ich mir ziemlich sicher, dass Sie das "% d" in der ersten Zeichenfolge durch "eins" ersetzen können.)

James Curran
quelle
8
Benötigt nicht einmal einen ternären Operator:printf("Total: %d item%s", cnt, "s" + (cnt==1));
MSalters
@MSalters, aber das ergibt eine doppelte Null am Ende der Zeichenfolge, was in anderen Situationen ein Problem sein kann, in denen doppelte Null etwas bedeutet (z. B. in einem lpStrFilterMitglied von OPENFILENAME-Strukturen )
Bobobobo
1
@bobobobo: Nein. Druckt %sbis zu, jedoch ohne die \0aus der Quellzeichenfolge .
MSalters
@ MSalters wie funktioniert das printf("Total: %d item%s", cnt, "s" + (cnt==1));?
Quirk
2
@Quirk: (cnt==1)ist wahr oder falsch, was in 0 oder 1 konvertiert wird. "S" ist ein Zeiger auf eine nicht terminierte Zeichenfolge. Beim Hinzufügen eines Zeichens wird ein Zeichen (das s) übersprungen. Dies druckt also entweder "s" oder "".
MSalters
3

Unabhängig vom kompilierten Code sind sie semantisch anders. <cond>?<true expr>:<false expr>ist ein Ausdruck und if..else..eine Aussage.

Obwohl die Syntax des bedingten Ausdrucks unangenehm erscheint, ist sie eine gute Sache. Sie müssen a angeben <false expr>und die beiden Ausdrücke werden typgeprüft.

Das Äquivalent zu einer if..else..ausdrucksbasierten, funktionalen Sprache wie Lisp ist Haskell ? :in C ++ anstelle von if..else..Anweisung.

amdyes
quelle
2

Sie sind nicht gezwungen, alles in eine Zeile zu setzen: -

x = y==1 ?
    2
    :// else
    3;

Es ist viel klarer als wenn / sonst, weil Sie sofort sehen können, dass beide Zweige dazu führen, dass x zugewiesen wird.

QuentinUK
quelle
Sie können auch eine const
QuentinUK
0

Ich würde erwarten, dass es auf den meisten Compilern und Zielplattformen Fälle gibt, in denen "wenn" schneller ist und Fälle, in denen ?: Schneller ist. Es wird auch Fälle geben, in denen eine Form mehr oder weniger kompakt ist als die andere. Welche Fälle die eine oder andere Form bevorzugen, hängt von Compilern und Plattformen ab. Wenn Sie leistungskritischen Code auf ein eingebettetes Mikro schreiben, überprüfen Sie, was der Compiler jeweils generiert, und finden Sie heraus, welcher Code besser ist. Auf einem "Mainstream" -PC besteht die einzige Möglichkeit, aufgrund von Caching-Problemen zu erkennen, welche besser ist, darin, beide Formen in einer Weise zu vergleichen, die der tatsächlichen Anwendung ähnelt.

Superkatze
quelle
0

In CA ist der ternäre Operator "?:" Verfügbar, um bedingte Ausdrücke des Formulars zu erstellen

exp1 ? exp2:exp3

Dabei sind exp1, exp2 und exp3 Ausdrücke

zum Beispiel

        a=20;
        b=25;
        x=(a>b)?a:b;

        in the above example x value will be assigned to b;

Dies kann mit der if..else- Anweisung wie folgt geschrieben werden

            if (a>b)
             x=a;
             else
             x=b;

** Daher gibt es keinen Unterschied zwischen diesen beiden. Dies ist für den Programmierer leicht zu schreiben, aber für den Compiler sind beide gleich. *

ksrao
quelle
0

Beim Umkehren eines Codes (an den ich mich vor einigen Jahren nicht mehr erinnere) habe ich einen einzeiligen Unterschied zwischen dem Maschinencode von :? und wenn-sonst. Don't remember much but it is clear that implementation of both is different.

Aber ich rate Ihnen, keinen von ihnen zu wählen, weil er effizient ist, sondern je nach Lesbarkeit des Codes oder Ihrer Bequemlichkeit. Viel Spaß beim Codieren

Pervez Alam
quelle
Der Unterschied war, dass einer von ihnen goto zum Verzweigen benutzte und der andere einen einheimischen Unterricht verwendete. Ich erinnere mich nicht, welcher welchen benutzte.
Pervez Alam
0

Der ternäre Operator gibt immer einen Wert zurück. In Situationen, in denen Sie einen Ausgabewert aus dem Ergebnis wünschen und es nur zwei Bedingungen gibt, ist es immer besser, den ternären Operator zu verwenden. Verwenden Sie if-else, wenn eine der oben genannten Bedingungen nicht erfüllt ist.

Raheel Afzal
quelle
6
Was ist das genau? Weißt du wovon du sprichst?
Quanten
0

Ich denke, dass es Situationen gibt, in denen das Inline-If aufgrund des Umfangs, in dem es funktioniert, "schnelleren" Code liefern kann. Das Erstellen und Zerstören von Objekten kann kostspielig sein. Betrachten Sie daher das folgende Szenario:

class A{
    public:
    A() : value(0) {
        cout << "Default ctor" << endl;
    }
    A(int myInt) : value(myInt)
    {
        cout << "Overloaded ctor" << endl;
    }

    A& operator=(const A& other){
        cout << "= operator" << endl;
        value = other.value; 
    }

    ~A(){
        cout << "destroyed" << std::endl;
    }

    int value;

};


int main()
{
   {
       A a;
       if(true){
           a = A(5);
       }else{
           a = A(10);
       }
   }

   cout << "Next test" << endl;
   {
        A b = true? A(5) : A(10);
   }
   return 0;
}

Mit diesem Code lautet die Ausgabe:

Default ctor                                                                                                                                                                                                                      
Overloaded ctor                                                                                                                                                                                                                   
= operator                                                                                                                                                                                                                        
destroyed                                                                                                                                                                                                                         
destroyed                                                                                                                                                                                                                         
Next test                                                                                                                                                                                                                         
Overloaded ctor                                                                                                                                                                                                                   
destroyed  

Indem wir das if einfügen, sparen wir eine Reihe von Operationen, die erforderlich sind, um aim gleichen Umfang wie am Leben zu bleiben b. Während es sehr wahrscheinlich ist, dass die Geschwindigkeit der Zustandsbewertung in beiden Szenarien ziemlich gleich ist, zwingt eine Änderung des Bereichs Sie dazu, andere Faktoren zu berücksichtigen, die Sie durch Inline-If vermeiden können.

Eric
quelle
Und was ist mitA a(true ? 5 : 10);
Quest
-1

Jetzt kann ich Ihnen dabei nicht helfen. Vielleicht kann ich Ihnen bei einer sekundären Frage helfen. Möchte ich sie verwenden? Wenn Sie nur die Geschwindigkeit wissen möchten, ignorieren Sie einfach meinen Kommentar.

Ich kann nur sagen, bitte seien Sie sehr schlau, wann Sie das Ternär verwenden sollen. : Operator. Es kann sowohl ein Segen als auch ein Fluch für die Lesbarkeit sein.

Fragen Sie sich, ob Sie dies leichter lesen können, bevor Sie es verwenden

int x = x == 1 ? x = 1 : x = 1;

if (x == 1)
{
   x = 1
}
else
{
   x = 2
}

if (x == 1)
    x = 1
else
    x = 1

Ja, es sieht dumm aus, den Code zu 100% falsch zu machen. Aber dieser kleine Trick hat mir geholfen, meine Lesbarkeit von Code zu analysieren. Es ist die Lesbarkeit des Operators, den Sie in diesem Beispiel betrachten, und nicht der Inhalt.

Es sieht sauber aus, aber auch der durchschnittliche Toilettensitz und Türknauf

Nach meiner begrenzten Erfahrung habe ich nur sehr wenige Menschen gesehen, die tatsächlich in der Lage waren, Informationen, die von einem ternären Operator benötigt wurden, schnell auszuliefern. Vermeiden Sie dies, es sei denn, Sie sind sich zu 100% sicher, dass es besser ist. Es ist ein Schmerz zu beheben, wenn es auch abgehört ist, denke ich

Proclyon
quelle
5
erste Zeile sollte wahrscheinlich lesen int x = x == 1 ? 1 : 2oder möglicherweiseint x = (x == 1) ? 1 : 2
Hasturkun
Mein Punkt war nur, die Ansicht des Codes zu zeigen, die Sauberkeit einer Zeile ist ja schön. Wenn Sie jedoch CONDITION / ASSIGNEMENT sehen möchten, kann der Inhalt des Codes gefälscht sein. Wenn Sie erkennen möchten, was Sie sehen, sehen Sie nur den Bediener und den Standort. Ich sehe das Wort IF und () ich weiß, ah, das ist eine Bedingung. Ich sehe A = B? ZUSTAND: ZUSTAND Haben Sie das sofort für sich selbst erkannt? Die meisten Leute, die ich kenne, wissen das nicht, vielleicht weil die meisten Leute, die ich kenne, Neulinge wie ich sind. Sie haben Recht mit den Zahlen, die Unsinn sind, das ist der Punkt.
Proclyon
2
Die erste Zeile benötigt definitiv einige Klammern. Vielleicht "int x = (y == 1)? 0: 1;" oder "int x = ((y == 1)? 0: 1);"
Supercat
6
Es tut mir leid, aber ich habe kein Problem damit, die Aufgabe zu sehen. Wenn Sie sich dafür entscheiden, das Beispiel zu komplizieren, um Ihren Standpunkt zu verdeutlichen, ist dies Ihr Problem. Warum schreibst du nicht x = x = 1;überall und beschwerst dich dann, dass die Zuordnung zu kompliziert ist und vermieden werden sollte?
OnkelBens
-4

Nein, sie werden in genau denselben ausführbaren Code konvertiert.

Alex F.
quelle
7
-1: Auf welcher Version von welchem ​​Compiler, auf welcher Plattform, mit welchem ​​Code?
Welpe
3
DeadMG: Natürlich VB6-Compiler!
Alex F