2016-06-24 20 views
0

Angenommen, wir folgenden Code haben:C++ switch-Anweisung Auswertung

switch (currentChar) { 
    case 'G': 
    case 'T':     
    case 'M': 
    case ';':      
    case '\r':      
    case '\n': 
     doSomething();  
     break; 
} 

Wenn die erste Bedingung erfüllt ist (currentChar == 'G') werden auch die folgenden Fälle verglichen, oder springt das Programm direkt auf doSomething()?

Was wäre schneller auszuführen: der Schalter-Fall, oder ein mit || Operator?

Klarstellung: I doSomething ausgeführt werden soll, wenn eine der Bedingungen erfüllt ist. Ich weiß auch, dass der "G" -Fall in etwa 99% aller Fälle auftreten wird. Kann ich davon ausgehen, dass es als erstes verglichen wird, wenn ich es auf die Liste setze?

+0

Folgende Anweisungen werden ebenfalls ausgewertet, bis sie eine Anweisung 'break;' erfüllen oder von der switch-Anweisung abfallen. –

+0

Es ist nicht klar, was Sie fragen. Die Fälle sind konstante Ausdrücke, und es macht keinen Unterschied, ob diese konstanten Ausdrücke ausgewertet werden. Fragen Sie, ob 'currentChar' mit diesen Fallwerten verglichen wird? Fragen Sie, ob 'doSomething()' ausgewertet wird? Oder fragst du etwas anderes? – hvd

+0

Sie können jeden Weg testen und selbst herausfinden. Im Allgemeinen Wie schnell sind Fragen zu weit, da sie von vielen verschiedenen Faktoren abhängen können. – NathanOliver

Antwort

3

Wenn die erste Bedingung (currentChar == 'G') werden die folgenden Fälle ausgewertet, oder springt das Programm direkt auf doSomething() erfüllt ist?

Es wird sofort springen doSomething()

Was schneller wären auszuführen auszuführen: der Schalter-Fall oder wenn mit || Operator?

Ich glaube nicht, dass es mit irgendeinem anständigen modernen C++ - Compiler einen Unterschied machen würde, und der ausgegebene Code sollte ziemlich gleich sein.

+0

Überprüfen Sie die Antwort, die ich gab. Ich schrieb ein Programm und es war schneller mit einer if-Anweisung. – Shiro

1

Was wäre schneller auszuführen: der Switch-Case oder ein if mit || Operator?

Gehen Sie für switch(). Wenn Sie eine Aufzählung oder eine ganze Zahl mit einem kleinen Wert festgelegt haben, erstellt switch() normalerweise eine Sprungtabelle.

0

Wenn die erste Bedingung erfüllt ist (currentChar == 'G') werden die folgenden Fälle ebenfalls ausgewertet, oder springt das Programm direkt zu doSomething()?

In Ihrem Beispiel wird es sofort zu doSomething() springen. Falls Sie nicht möchten, dass dieses Verhalten haben, dann müssen Sie break Anweisungen einzufügen, wie unten für einen Fall gezeigt:

switch (currentChar) { 
    case 'G': /*things to be done */ break /* This break will take it out of switch*/; 
    case 'T':     
    case 'M': 
    case ';':      
    case '\r':      
    case '\n': 
     doSomething();  
     break; 
} 

Beachten Sie auch, dass in Ihrem Beispiel ist break nicht erforderlich, da es das ist letzte Aussage Ihrer switch-Anweisung. Bitte beachten Sie this Link für ein funktionierendes Beispiel von switch-Anweisung.

Was wäre schneller auszuführen: der Schalter-Fall oder ein If mit || Operator?

Unter der Annahme, dass Sie einen anständigen Compiler verwenden, ist der Unterschied minimal, so dass es ignoriert werden kann. Bitte beziehen Sie sich auf this So Link, falls Sie mehr Details wissen müssen.

bearbeiten für Ihre Klarstellung:

Ich möchte doSomething() zu ausgeführt werden, wenn eine der Bedingungen erfüllt ist.

Ja, gemäß Ihrem Code wird doSomething() ausgeführt, auch wenn nur eine der Bedingungen erfüllt ist.

Ich weiß auch, dass der 'G' Fall in etwa 99% aller Fälle auftreten wird. Kann ich davon ausgehen, dass es als erstes verglichen wird, wenn ich es auf die Liste setze?

Die verbleibenden Fälle werden nicht überprüft.

+0

break da ist notwendig, nicht für die ordnungsgemäße Kompilation obwohl. – Slava

+0

@Slava Entschuldigung, könnten Sie genauer sein? –

+0

ist es besser, 'break' in die letzte Anweisung zu setzen, auf der einen Seite ignoriert der Compiler das, auf einer anderen - wenn Sie nach der letzten ein weiteres Label hinzufügen, werden Sie keine Überraschungen bekommen. IE es ist zu einfach, einen Bug zu erstellen, wenn es keine Pause gibt. – Slava

0

Wenn die erste Bedingung (currentChar == ‚G‘) werden die folgenden Fällen auch ausgewertet werden, oder springt das Programm direkt auf doSomething() erfüllt ist?

Es fällt durch, bis es eine break findet oder das Ende erreicht.

1

Sobald currentChar mit 'G' verglichen wird, springen Sie zur Anweisung doSomething(). Sie können sich nicht auf die Reihenfolge Ihrer Fälle verlassen "optimieren" die switch.

Beachten Sie, dass der Vergleich nicht sequentiell erforderlich ist.
switch kann als Sprungtabelle zum Beispiel realisiert werden:

void foo_switch(char c) 
{ 
    switch (c) { 
     case '0': bar0(); break;   
     case '1': bar1(); break;   
     case '2': bar2(); break;   
     case '3': bar3(); break;   
    }; 
} 

void foo_if(char c) 
{ 
    if (c == '0') { 
     bar0(); 
    } else if (c == '1') { 
     bar1(); 
    } else if (c == '2') { 
     bar2(); 
    } else if (c == '3') { 
     bar3(); 
    } 
} 

void foo_table(char c) 
{ 
    if ('0' <= c && c <= '3') { 
     using voidFPtr = void(*)(); 
     voidFPtr funcs[] = {&bar0, &bar1, &bar2, &bar3}; 
     funcs[c - '0'](); 
    } 
} 
+0

Hi was meinst du mit "_comparison ist nicht notwendig sequentiell. _" und könntest du bitte ein Grunddesign eines Sprungtisches liefern? –

+0

@Nope: Siehe 'foo_table' in Bearbeitung. – Jarod42

0

Was auszuführen wäre schneller: der Schalter-Fall oder wenn mit || Operator?

Sie sollten sich Sorgen über die Lesbarkeit und die Unterstützung von Code machen, also verwenden Sie, was für Sie besser lesbar ist. Dann, wenn Sie Probleme mit der Programmgeschwindigkeit haben, arbeiten Sie an der Optimierung.

Zur besseren Lesbarkeit - natürlich, die subjektiv, aber mit Schalter, den Sie bekommen weniger ausführlich Code, wie Sie Variablennamen nicht mehrmals wiederholen müssen:

if(currentChar == 'G' || currentChar == 'B' || currentChar == 'C') 

so würde ich Schalter in dieser Situation vorziehen.

0
switch (currentChar) { 
    case 'G': 
    case 'T':     
    case 'M': 
    case ';':      
    case '\r':      
    case '\n': 
     doSomething();  
     break; 
} 

Dies macht doSomething() aufgerufen werden, wenn currentCharG ist, T, M, ;, \r oder \n. Es ist schneller, eine switch als nur einfach if zu verwenden, weil switch Anweisungen oft in Sprungtabellen optimiert sind. Deshalb muss ein Schalter mit einem konstanten Integralwert arbeiten.

0

Es gibt keine Garantie für die Reihenfolge der Prüfung in einem Schaltergehäuse. Es gibt auch keine Garantie für die Reihenfolge der Ausführung von ||, wenn es keine Nebenwirkungen für die Ausdrücke gibt.
Im Grunde, wenn der einzige Unterschied das Timing ist, garantiert C++ nichts über die Reihenfolge der Dinge auf der Basis der Als-ob-Regel.

+0

'a || b 'ist kurzgeschlossen und garantiert nicht' b 'zu bewerten, wenn' a 'als wahr bewertet wird (es sei denn, Sie überlasten es natürlich). '5.15 [expr.log.or]' – user975989

+0

@ user975989: Wie gesagt, wenn a und b keine Nebenwirkungen haben, erlaubt die as-if-Regel dem Compiler, den Operator in irgendeiner Weise zu implementieren, die das gleiche Ergebnis liefert – Dani

1

Fragen zum Leistungsergebnis eines bestimmten Codes sind fast immer Zeitverschwendung.

Hier ist, wie gcc5.3 beschäftigt sich mit diesem Code nach einem Optimierungsdurchlauf:

test(char): 
     cmpb $59, %dil 
     je  .L3  
     jle  .L6  
     cmpb $77, %dil 
     je  .L3 
     cmpb $84, %dil 
     je  .L3 
     cmpb $71, %dil 
     je  .L3 
.L1: 
     rep ret 
.L6: 
     cmpb $10, %dil 
     je  .L3 
     cmpb $13, %dil 
     jne  .L1 
.L3: 
     jmp  doSomething() 

ich Sie glaube nicht, dass wirklich etwas schneller, ohne eine 256-Eintrag Sprungtabelle schreiben könnte, das seine eigene hätte Konsequenzen in Bezug auf Cache-Lokalität und Erschöpfung.