[if - else if - else] oder [switch - case - default] ?



  • Welcher Ausdruck ist logischer, besserer Stil, effizienter, ...?

    switch (a) {
    case 0:
      // do something
      break;
    case 1:
      // do something
      break;
    default:
      // so something
      break;
    }
    

    oder

    if (a == 0) {
      // do something
    } else if (a == 1) {
      // do something
    } else {
      // do something
    }
    

    Es geht hierbei um genau die Situation mit *2* Spezialfällen und einem Defaultfall!

    Gruss



  • Das was dir besser gefällt. Ich tendiere zum switch.



  • Tomahawk schrieb:

    Welcher Ausdruck ist logischer, besserer Stil, effizienter, ...?

    Alle drei Punkte verbucht das if für sich.



  • Zwei Antworten - Zwei Meinungen 🙄



  • Naja bei der Effizienz würde ich von modernen Compilern schon erwarten, dass sie das if auch mit einer Symboltabelle wie beim switch umsetzen (wer mags nachprüfen?).
    Mir persönlich gefällt bei nur 3 Fällen if besser, ich finde ein switch "lohnt" sich erst bei mehr Werten.

    Am Ende ist es wirklich eine Sache des Geschmacks.



  • volkard schrieb:

    Tomahawk schrieb:

    Welcher Ausdruck ist logischer, besserer Stil, effizienter, ...?

    Alle drei Punkte verbucht das if für sich.

    Da muss ich dir leider widersprechen. Bei mir erzeugen beide Konstrukte den selben Code. Somit ist keiner von beiden effizienter. Logischer und besserer Stil sind einfach Geschmacksfragen.



  • Tomahawk schrieb:

    Welcher Ausdruck ist logischer

    Das hängt vom Kontext und mehr noch von Deinem Geschmack ab.

    Tomahawk schrieb:

    [...] besserer Stil[...]

    Das hängt vom Kontext und mehr noch von Deinem Geschmack ab.

    Tomahawk schrieb:

    [...]effizienter, ...?

    Das hängt vom Compiler ab, wobei ich schätze, dass mehr Optimierungspotential beim Switch-Case besteht.



  • HighLigerBiMBam schrieb:

    Da muss ich dir leider widersprechen. Bei mir erzeugen beide Konstrukte den selben Code.

    Bei mir nicht. Aber bei 2 Spezialfällen sehe ich auch keinen Performance-Unterschied.



  • Als kurzen Einwand noch: Stilmäßig finde ich switch immer dann besser wenn es um enums geht. Da kann der Compiler auch hübsch bei vergessenen Konstanten warnen.

    MfG SideWinder



  • Bei nur zwei Fällen tendiere ich auch eher zu if...else if...., allerdings hat er ja auch nur bei werten die als integer dargestellt werden können die Wahl. Denn bei std::string zum Beispiel kann er ohne Umwege switch gar nicht nutzen.

    Lg freeG



  • volkard schrieb:

    HighLigerBiMBam schrieb:

    Da muss ich dir leider widersprechen. Bei mir erzeugen beide Konstrukte den selben Code.

    Bei mir nicht. Aber bei 2 Spezialfällen sehe ich auch keinen Performance-Unterschied.

    Das finde ich aber dann ziemlich dämlich von den Compilerbauern. Dieser müsste in genau diesem speziellen Fall doch sehen, dass es wie ein if else gebraucht wird. Nun gut ich würde gerne den Fall sehen, wo dies bei dir nicht gleichen Code bei identischer Logik bringt.



  • HighLigerBiMBam schrieb:

    volkard schrieb:

    HighLigerBiMBam schrieb:

    Da muss ich dir leider widersprechen. Bei mir erzeugen beide Konstrukte den selben Code.

    Bei mir nicht. Aber bei 2 Spezialfällen sehe ich auch keinen Performance-Unterschied.

    Das finde ich aber dann ziemlich dämlich von den Compilerbauern. Dieser müsste in genau diesem speziellen Fall doch sehen, dass es wie ein if else gebraucht wird. Nun gut ich würde gerne den Fall sehen, wo dies bei dir nicht gleichen Code bei identischer Logik bringt.

    #include <iostream>
    using namespace std;
    
    int main(){
    int a;
    cin>>a;
    #if 0
    switch (a) {
    case 0:
      cout<<"hallo\n";
      break;
    case 1:
      cout<<"welt\n";
      break;
    default:
      cout<<"nix\n";
      break;
    } 
    #else
    if(a==0)
      cout<<"hallo\n";
    else if(a==1)
      cout<<"welt\n";
    else
      cout<<"nix\n";
    #endif
    }
    
    g++ -march=native -DNDEBUG --save-temps -O3 main.cpp
    
    movl	12(%rsp), %eax
    	testl	%eax, %eax
    	jne	.L8
    	movl	$6, %edx
    	movl	$.LC0, %esi
    	movl	$_ZSt4cout, %edi
    	call	_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    	xorl	%eax, %eax
    	addq	$24, %rsp
    	.cfi_remember_state
    	.cfi_def_cfa_offset 8
    	ret
    	.p2align 4,,7
    	.p2align 3
    .L8:
    	.cfi_restore_state
    	decl	%eax
    	je	.L9
    	movl	$4, %edx
    	movl	$.LC2, %esi
    	movl	$_ZSt4cout, %edi
    	call	_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    	xorl	%eax, %eax
    	addq	$24, %rsp
    	.cfi_remember_state
    	.cfi_def_cfa_offset 8
    	ret
    	.p2align 4,,7
    	.p2align 3
    .L9:
    	.cfi_restore_state
    	movl	$5, %edx
    	movl	$.LC1, %esi
    	movl	$_ZSt4cout, %edi
    	call	_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    	xorl	%eax, %eax
    	addq	$24, %rsp
    	.cfi_def_cfa_offset 8
    	ret
    	.cfi_endproc
    
    movl	12(%rsp), %eax
    	testl	%eax, %eax
    	je	.L6
    	decl	%eax
    	je	.L7
    	movl	$4, %edx
    	movl	$.LC2, %esi
    	movl	$_ZSt4cout, %edi
    	call	_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    	xorl	%eax, %eax
    	addq	$24, %rsp
    	.cfi_remember_state
    	.cfi_def_cfa_offset 8
    	ret
    	.p2align 4,,7
    	.p2align 3
    .L6:
    	.cfi_restore_state
    	movl	$6, %edx
    	movl	$.LC0, %esi
    	movl	$_ZSt4cout, %edi
    	call	_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    	xorl	%eax, %eax
    	addq	$24, %rsp
    	.cfi_remember_state
    	.cfi_def_cfa_offset 8
    	ret
    	.p2align 4,,7
    	.p2align 3
    .L7:
    	.cfi_restore_state
    	movl	$5, %edx
    	movl	$.LC1, %esi
    	movl	$_ZSt4cout, %edi
    	call	_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    	xorl	%eax, %eax
    	addq	$24, %rsp
    	.cfi_def_cfa_offset 8
    	ret
    	.cfi_endproc
    

    Wie gesagt, ich sehe keinen Performance-Unterschied. Aber die if-Version verteilt den Verzweigungscode weniger.



  • Mit switch kann man auch Sachen machen die mit if/else nur schwer (unübersichtlich) möglich sind.
    zb. das hier

    switch(int)
    {
    case 0:
    case 1:
    case 2:
    case 3:
      machwas_zuerst();
    case 4:
      kurz_das_noch();
    case 5:
    case 6:
      so_jetzt_passt_es;
      break;
    
    default:
      break;
    }
    

    Wieso sollte ich also im Code zwei verschiedene Stil haben?
    switch/case ist auch fehlerfreier weil hier sicher ist das immer mit == verglichen wird.

    Lichtlein



  • Optimiert der Compiler das zu den if-Abfragen? Wenn der hier für jedes case ein == macht, wäre das nämlich ziemlich doof.



  • Der Compiler wird daraus eine Sprungtabelle machen, denke ich. Was Lichtlein sagen wollte war das man z.B. nicht ausversehen if (x = a) schreiben kann.



  • Lichtlein schrieb:

    switch(int)
    {
    case 0:
    case 1:
    case 2:
    case 3:
      machwas_zuerst();
    case 4:
      kurz_das_noch();
    case 5:
    case 6:
      so_jetzt_passt_es;
      break;
    
    default:
      break;
    }
    

    Schön wären natürlich reale Beispiele: man kann auch 13 Schleifen verschachteln, und dann von Schleife 9 bei einer bestimmten Bedingung in Schleife 2 springen und das als Argument für goto nehmen.



  • Lichtlein schrieb:

    Wieso sollte ich also im Code zwei verschiedene Stil haben?

    Das wäre aber ein Grund, switch nicht mehr zu nehmen und nur noch if. Denn das geht auch mit strings.

    Lichtlein schrieb:

    switch/case ist auch fehlerfreier weil hier sicher ist das immer mit == verglichen wird.

    Kein Argument. Die Compilerwearnungen sollten schon an sein.



  • Volkard schrieb:

    ...

    Danke. Den kleinen Unterschied habe ich beim Überfliegen übersehen. In dem Fall hat switch sogar ein ".cfi_restore_state" mehr wenn der else/default-Zweig getroffen wird.



  • ipsec schrieb:

    Schön wären natürlich reale Beispiele

    Dann wird's bei drei Fällen bleiben, vermute ich:
    - Menüschleife in Konsolenanwendung,
    - switch über enum,
    - Duffs Device.



  • klöklö schrieb:

    Der Compiler wird daraus eine Sprungtabelle machen, denke ich. Was Lichtlein sagen wollte war das man z.B. nicht ausversehen if (x = a) schreiben kann.

    Ach komm, ich bin der Meister der Flüchtigkeitsfehler, aber das ist mir die letzten 5 Jahre nicht passiert.


Anmelden zum Antworten