2010-07-29 9 views
6

Ich bin interessiert, wenn es ein Unterschied von der C- oder C++ Perspektive Compiler ist, ob ich verwende:Gibt es einen Unterschied in C und C++ zwischen der Verwendung von if, else if, else if, ... und der Verwendung von switch() {case A: ... case B: ...}?

if (value == a) { 
    ... 
} 
else if (value == b) { 
    ... 
} 
else if (value == c) { 
    ... 
} 

gegen

switch (value) { 
    case a: 
     ... 
     break; 
    case b: 
     ... 
     break; 
    case c: 
     ... 
     break; 
} 

Es mir die Ansicht, dass es keinen Unterschied, nur syntaktischer. Weiß jemand mehr darüber?

Danke, Boda Cydo.

Antwort

6

Es gibt einen Unterschied - mit switch'es kann der Compiler den Switch optimieren, um eine Nachschlagetabelle zu verwenden. Dies kann möglich sein, wenn viele Werte nahe genug beieinander liegen. Zum Beispiel dieser Schalter:

switch (integer) { 
    case 10: 
    xxx 
    break; 
    case 12: 
    yyy 
    break; 
    case 13 
    zzz 
    break; 
} 

könnte werden (Pseudo-Code):

address = lookup[ integer - 10 ]; // which is prefilled with { case_10, err, err, case_12, case 13 } 
goto address; 
case_10: xxx; goto err; 
case_12: yyy; goto err; 
case_13: zzz; 
err: //do nothing 
+0

Mit 'if's kann der Compiler unter bestimmten Umständen den 'if'-Baum optimieren, um eine Nachschlagetabelle zu verwenden. Dies ist mit aktuellen Compilern viel weniger wahrscheinlich, aber es geht nicht über das hinaus, was der Standard sagt. –

0

Ein Schalter sollte zu einem Sprung mit indirekter Adressierung kompiliert werden, während eine Sequenz von if-Anweisungen eine Kette von bedingten Sprüngen sein wird. Der erste ist konstante Zeit; natürlich können Sie viel mehr allgemeine Bedingungen in ein if setzen.

Edit: Ich sollte erwähnen, dass ich nicht überrascht wäre, wenn einige intelligente Compiler erkennen können, dass alle Bedingungen in einer Kette von ifs eine bestimmte einfache Form haben und zu einem Schalter konvertieren. Ich weiß nicht, ob sie das tun, aber Sie können immer dekompilieren und überprüfen.

8

Ja, es gibt Unterschiede. Die kaskadierten if s garantieren die Bewertung der Bedingungen in der Reihenfolge. Der Schalter garantiert nur eine einzige Auswertung dessen, was als Schalterparameter verwendet wird. Abhängig vom Compiler wird der Switch oft (fast) konstante Zeit unabhängig vom gewählten Zweig nehmen, während die if Kaskade so ziemlich garantiert, dass das erste Bein das schnellste, das zweitschnellste und so weiter ist, bis das letzte am langsamsten ist .

+2

Es ist nicht ganz so einfach. Wenn die Bedingung keine Nebeneffekte hat (wie im OP), kann der Compiler ein if/else ziemlich leicht neu anordnen. Zum Beispiel kann [gcc] (http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Optimize-Options.html#Optimize-Options) dies mit Optionen wie '-freorder-blocks' und. Tun '-fGuess-Zweigwahrscheinlichkeit'. Der Compiler kann unter Umständen auch in der Lage sein, aus einer if-Kaskade eine Sprungtabelle zu generieren. Schließlich führen 'switch'-Anweisungen nicht zu einer Jump-Tabelle, wenn die Werte zu spärlich sind. –

1

Dies hängt davon ab, wie der Compiler Ihren Code optimiert. Code-Optimierung für einen Compiler ist ein riesiges Feld.

Um die genaue Antwort für Ihren Compiler zu finden, bestimmen Sie, wie Sie Assembly-Code mit ihm erstellen und den verschiedenen Assembly-Code betrachten, der in die Datei geschrieben wird.

Dies wurde bereits mit einem Compiler gemacht und Sie können die Ergebnisse hier sehen. http://www.eventhelix.com/RealtimeMantra/Basics/CToAssemblyTranslation3.htm

Aber die kurzen kurzen Antworten ist ja. sie werden höchstwahrscheinlich anders sein.

0

Die case-Anweisung kompiliert bekommen kann ein „Sprungtabelle“, die schneller sein kann, wenn es Dutzende von Fällen und Sie Führe das Millionen von Malen aus.

0

Wenn der select-Wert eine Ganzzahl ist (die in C/C++ sein muss), ist es möglich, dass der Compiler die ifs durch eine Sprungtabelle ersetzt.

3

Es gibt einige Unterschiede, nach dem Standard.

  1. Die value kann mehrmals in der if Kette, einmal switch in der Anweisung ausgewertet werden. Wenn value keine Nebenwirkungen hat, ist das unwichtig.
  2. Die if-Kette lässt keinen Fallthrough zu, während die switch-Anweisung einen Fallout ohne break aufweist.
  3. Die if-Kette ermöglicht einen allgemeinen Vergleich, aber die switch-Anweisung ermöglicht nur Vergleiche mit konstanten Integralausdrücken.
  4. Die Verwendung von break; ist anders. Es bricht aus der switch Erklärung, aber weiter. Wenn Sie aus einer Schleife ausbrechen oder switch Anweisung je nach Bedingung einschließen müssen, benötigen Sie die if Kette.
  5. Da eine switch Aussage im Wesentlichen funktioniert ein goto zu einer case Anweisung oder default:, wird es an verschiedenen Orten arbeiten, die Quintessenz Beispiel Duff's device zu sein. (IIRC, als Tom Duff es ein starkes Argument in der Frage der Durchfall, aber er war, auf welcher Seite sich nicht sicher.)

Also, wenn value ohne Nebenwirkungen ausgewertet wird, werden break; Anweisungen verwendet konsequent und nur in der switch, der Vergleich ist zu konstanten integralen Werten, und es ist nicht auf eine funky Weise verwendet, kann das Verhalten identisch sein. Ob ein Compiler diese Äquivalenz verwendet, ist eine andere Frage.

0

+1 für David Thomleys Antwort, da ich das wirklich am vollständigsten finde.

Eine wichtige Sache fehlt jedoch, das heißt, dass case Etiketten müssen konstante Ausdrücke, die zur Kompilierzeit auswerten. Mit if werden beide Seiten des Vergleichs (wenn Sie die if-Anweisung dazu reduzieren) zur Laufzeit ausgewertet.

1

Ich kam zu dem gleichen Problem, damit ich ein paar Tests habe, hier sind einige Ergebnisse 3.4.6 gcc-Version unter Verwendung/CentOS 4

ac und cc Verwendung ifs, aber cc nimmt die Variable von der Kommandozeile so Der Compiler kennt den Wert von "b" zur Kompilierzeit nicht. b.c verwendet

Quellcodes wechseln:

A. C

#include <stdint.h> 
int main(){ 
uint32_t i,b=10,c; 
    for(i=0;i<1000000000;i++){ 
     if(b==1) c=1; 
     if(b==2) c=1; 
     if(b==3) c=1; 
     if(b==4) c=1; 
     if(b==5) c=1; 
     if(b==6) c=1; 
     if(b==7) c=1; 
    } 
} 

b.c

#include <stdint.h> 
int main(){ 
uint32_t i,b=10,c; 
    for(i=0;i<1000000000;i++){ 
     switch(b){ 
     case 1: 
       c=1; 
       break; 
     case 2: 
       c=1; 
       break; 
     case 3: 
       c=1; 
       break; 
     case 4: 
       c=1; 
       break; 
     case 5: 
       c=1; 
       break; 
     case 6: 
       c=1; 
       break; 
     case 7: 
       c=1; 
       break; 
     } 
    } 
} 

C.C

#include <stdint.h> 
int main(int argc, char **argv){ 
uint32_t i,b=10,c; 

    b=atoi(argv[1]); 
    for(i=0;i<1000000000;i++){ 
     if(b==1) c=1; 
     if(b==2) c=1; 
     if(b==3) c=1; 
     if(b==4) c=1; 
     if(b==5) c=1; 
     if(b==6) c=1; 
     if(b==7) c=1; 
    } 
} 

ersten kompilieren wir die Programme ohne Optimierung Fahnen:

Die Ergebnisse sind wie ich dachte, Schalter ist schneller als wenn keine Compiler-Optimierung verwendet wird.

Jetzt erstellen wir -O2 mit:

[email protected] ~ # gcc a.c -o a -O2;gcc b.c -o b -O2;gcc c.c -o c -O2 
[email protected] ~ # time ./a 

real 0m0.055s 
user 0m0.055s 
sys  0m0.000s 
[email protected] ~ # time ./b 

real 0m0.537s 
user 0m0.535s 
sys  0m0.001s 
[email protected] ~ # time ./c 10 

real 0m0.056s 
user 0m0.055s 
sys  0m0.000s 

Überraschung Überraschung, beide Programme (A. C und C. C.) mit ifs sind schneller als Schalter (etwa 10 mal!).

Verwandte Themen