Forum: PC-Programmierung Code optimieren, switch case ersetzen


von Michael (Gast)


Lesenswert?

Hallo Zusammen,

vllt. kann einer mal n paar Minuten spendieren und sich des anschauen !

Habe eine paar +defines

#define ausdruck_1   0xA
#define ausdruck_2   0xB
#define ausdruck_3   0xC

jetzt empfange ich Daten und schau entsprechend was als Parameter 
übergeben werden soll !

if(data == TRUE)
{
   switch(data)
      case a:
       function(ausdruck_1);
       break;
      case b:
       function(ausdruck_2);
       break;
      case c:
       function(ausdruck_3);
       break;

}

es ist so, dass ich aber 15 Varianten empfangen kann, daher wäre mein 
Switch Case 15 Optionen gross !
Kann man die 15 switch cases irgendwie anders ersetzen, durch einen 
verschachtelten Ausdruck ?

Danke

Gruß
Michael

von Mike (Gast)


Lesenswert?

Was steht denn in der Variable data drin?
Wenn du es schaffst, dass die Werte deiner defines in data steht, dann 
kannst du die Funktion direkt mit dem Argument data aufrufen.

von Frank (Gast)


Lesenswert?

1
if(data == TRUE)
2
{
3
switch(data)
4
...
5
}

Pfui, pfui, pfui!
Was ist Data denn für ein Datentyp?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Michael schrieb:
> Kann man die 15 switch cases irgendwie anders ersetzen, durch einen
> verschachtelten Ausdruck ?

Sicher, aber warum sollte man das tun? Der Compiler optimiert so ein 
switch-case-Statement, genauso wie er Deinen "verschachtelten Ausdruck" 
optimiert - und beide werden ziemlich ähnlichen Code und ziemlich 
ähnliche Geschwindigkeit ergeben.

FÜr Dich gibt das nur Nachteile - der "verschachtelte Code" ist deutlich 
schlechter zu lesen und zu warten als das switch-case-Statement.


Die einzige Möglichkeit, hier etwas mehr Performance zu erzielen, 
setzt voraus, daß die Anzahl der Variationen und der Werteumfang 
lückenlos ist. Das wäre eine Tabelle aus Funktionspointern, die über 
Deine Variable indiziert und aufgerufen werden. Allerdings macht ein gut 
optimierender Compiler eh' so ziemlich dasselbe, so daß der 
Performancegewinn hier wirklich überschaubar sein dürfte.



Aber bevor Du Dir über so etwas den Kopf zerbrichst, solltest Du Dir 
noch mal Deinen oben gezeigten Code genauer ansehen:
1
if(data == TRUE)
2
{
3
  switch(data)
4
    case a:

Wenn "data" == TRUE ist, kann es nicht auch 'a' oder 'b' etc. sein.

Da hast Du irgendwas recht grundlegendes noch nicht so ganz verstanden.

von Daniel A. (daniel-a)


Lesenswert?

Es kommt ganz darauf an, wie data und ausdruck_X zusammenhängen, in 
welchem Bereich sich data bewegt, etc. Ich würde jedoch nicht mit einem 
Performacezuwachs rechnen, oder einer Verkleinerung der Binaries 
rechnen, der GCC kann vieles optimieren.

Wenn man ausdruck_X von data berechnen kann, würde das switch sofort 
entfallen. Falls die 15 Werte von data direckt aufeinanderfolgen, 
könnte man eine Lookuptabelle der Form ausdruck=lookuptable[data] 
machen, dann brauchte man aber eine Bereichsprüffung der form 
if(data<lookuptable_size).

Ohne genauere Informationen zu den Werten kann man hier nichts genaueres 
sagen.

von Philip K. (pulsewidthmodul)


Lesenswert?

Rufus Τ. F. schrieb:
> Wenn "data" == TRUE ist, kann es nicht auch 'a' oder 'b' etc. sein.
>
> Da hast Du irgendwas recht grundlegendes noch nicht so ganz verstanden.

Nach meinem Verständnis von C ist alles, was nicht 0 ist automatisch 
True. Vereinfachend könnte man auch einfach schreiben
1
if (data)
2
{
3
  switch(data)
4
     case a:

von mh (Gast)


Lesenswert?

Philip K. schrieb:
> Nach meinem Verständnis von C ist alles, was nicht 0 ist automatisch
> True.


Naja, wenn Du behauptest
> if (data)
> {
>   switch(data)
>      case a:

wäre das gleiche wie

> if(data == TRUE)
> {
>   switch(data)
>     case a:

solltest Du Dein Verständnis aber nochmal "überarbeiten"...

Da müsstest Du mir mal die Definition von "TRUE" zeigen.
#define TRUE !0 ??? ;-)

von Michael (Gast)


Lesenswert?

Hallo, also
#defines ausdruck_1 generierte_groesse
enthält später einen generierten wert, anfangs nicht bekannt ist !

"data" hat eine Befehlsnummer drin stehen, anhand welcher 
dementsprechend ein bestimmtes Parameter übergeben werden soll ! "data" 
und generierte_groesse haben einen nicht identischen Inhalt !

von Dunno.. (Gast)


Lesenswert?

Sieht für mich aus als sollte je nach  empfangenem datum eine einzelne 
funktion mit unterschiedlichen Parametern aufgerufen werden, die nicht 
identisch mit dem Datum,  aber eindeutig zuzuordnen sind...?

Da geht sicher auch ein enum oder eine lut für..

von Philip K. (pulsewidthmodul)


Lesenswert?

mh schrieb:
> #define TRUE !0 ??? ;-)

Das muss gar nicht ich definieren, das ist in C standardmässig so. ;)

> The reason is that in the C programming language dosen't have a concept of a 
Boolean variable, i.e. a type class that can be either true or false. >Why bother 
when we can use numerical values. In C true is represented by >any numeric value 
not equal to 0 and false is represented by 0. This fact >is usually well hidden 
and can be ignored, but it does allow you to write
>
>if(a != 0) just as if(a)

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Michael schrieb:
> Kann man die 15 switch cases irgendwie anders ersetzen, durch einen
> verschachtelten Ausdruck ?

Könnte man schon machen, aber warum? Genau für so etwas ist Switch 
gedacht, und 15 ist jetzt nicht wirklich viel. Das kann auch mehrere 
tausend cases abdecken.

Lass es, wie es ist, das ist völlig in Ordnung.

Oliver

von Daniel A. (daniel-a)


Lesenswert?

Philip K. schrieb:
>>if(a != 0) just as if(a)

Nur ist es ein Unterschied, ob man a==1 oder a==0 vergleicht.
Ab c99 glaub ich hat man _Bool eingeführt, in c++ war er glaub ich schon 
immer. (int)(_Bool)6 ergibt 1. Aber 6 == true ist unwahr, weil das 6 == 
(int)true oder 6 == 1 entspricht. Umgekehrt würde ((_Bool)a) == 1 war 
sein, wobei man sich nicht darauf verlassen sollte, und statdessen besse 
soetwas macht: !!a == true.

Edit: http://codepad.org/YX4Z4sgk

: Bearbeitet durch User
von Fritz G. (fritzg)


Lesenswert?

if (data) ist was anderes als if (data == TRUE).

Der erste Ausdruck ist wahr, wenn data ungleich Null ist, der zweite 
Ausdruck ist wahr, wenn data genau eins ist.

von Programmiersprachentheaterintendant (Gast)


Lesenswert?

> #defines ausdruck_1 generierte_groesse
> enthält später einen generierten wert, anfangs nicht bekannt ist !

Dir nicht bekannt, aber wenn der Präprozessor durch ist, steht der 
wert fest noch bevor der Kompiler aufgerufen wird.
Viel Glück wenn der Präprozessor da einen Ausdruck m. Variablen 
hinrerlässt: Tester solchen Codes will ich NICHT sein ...

Wie würde eine berechnende Funktion d2gg()
1
generierte_grösse = d2gg(data);
Aussehen?

Respektive
1
if(NO_OPCODE != data) {
2
  function(d2gg(data));
3
}

Ich gehe davon aus dass Du in Deinem Eröffnungsbeitrag mit Absicht 3x 
die selbe *function(...) * hingeschrieben hast.

von Rolf M. (rmagnus)


Lesenswert?

Philip K. schrieb:
> mh schrieb:
>> #define TRUE !0 ??? ;-)
>
> Das muss gar nicht ich definieren, das ist in C standardmässig so. ;)

Unsinn.

>> The reason is that in the C programming language dosen't have a concept
>> of a Boolean variable,

Das stimmt schon seit 1999 nicht mehr.

>> i.e. a type class that can be either true or false. Why bother
>> when we can use numerical values. In C true is represented by
>> any numeric value not equal to 0 and false is represented by 0.

Das ist unpräzise formuliert, und es bedeutet selbstverständlich auch 
nicht, dass, wenn man zwei beliebige Werte, die nicht 0 sind, 
miteinander vergleicht, das Ergebnis immer wahr ist.

>> This fact is usually well hidden and can be ignored, but it does allow
>> you to write
>> if(a != 0) just as if(a)

Das stimmt, zwar, aber daraus kann man nicht schließen, dass
1
if (a == 1)
ebenfalls das selbe ist.

: Bearbeitet durch User
von Erwin D. (Gast)


Lesenswert?

Fritz G. schrieb:
> if (data) ist was anderes als if (data == TRUE).
>
> Der erste Ausdruck ist wahr, wenn data ungleich Null ist, der zweite
> Ausdruck ist wahr, wenn data genau eins ist.

Das würde ja bedeuten, dass TRUE als 1 definiert ist. Meines Wissens 
nach, und ich habe es auch noch nicht anders gesehen, wird FALSE als 0 
definiert und TRUE als !FALSE (und nicht als 1).
Damit wären die beiden Ausdrücke wieder identisch!

von mh (Gast)


Lesenswert?

Philip K. schrieb:
> mh schrieb:
>> #define TRUE !0 ??? ;-)
>
> Das muss gar nicht ich definieren, das ist in C standardmässig so. ;)

OK, also bleibst Du der Ansicht, dass
1
if (data)
nur eine Vereinfachung von
1
if(data == TRUE)
ist, also dass beide Ausdrücke nur unterschiedliche Schreibweisen sind 
mit der gleichen Funktion?

von Ingo L. (corrtexx)


Lesenswert?

1
 if( data ){ 
2
     switch(data){
3
       case a: function(ausdruck_1); break;
4
       case b: function(ausdruck_2); break;
5
       default: break; 
6
     }
7
 }
Super kompakt und übersichtlich

von Fritz G. (fritzg)


Lesenswert?

Ich suche grad, wie TRUE definiert ist. Ich kann es für den avr-gcc 
nicht finden, scheint ein Compiler-buildin zu sein.
Es gibt allerdings in stdbool.h folgendes:
1
#define true    1
2
#define false   0

von Mark B. (markbrandis)


Lesenswert?

1
if(data == TRUE)

Wozu überhaupt diese Abfrage?

In einem switch...case hat man immer auch einen default-case. Damit 
kann man alle Werte erschlagen, die keine Aktion auslösen sollen.

Außerdem ist es, je nachdem wie TRUE definiert ist, logisch falsch es so 
zu schreiben.

if(data)

und

if(data == TRUE)

ist eben nicht automatisch dasselbe.

von Peter D. (peda)


Lesenswert?

Ob 1 oder !0, beides wird zu 1 compiliert.
Der Compiler muß für TRUE immer 1 liefern.
Selber kann man im aber alles !0 übergeben und er wird es als TRUE 
evaluieren.
Um das in Code leicht ersichtlich zu machen, schreibt man daher oft:
1
if( !!data == TRUE )

von Fritz G. (fritzg)


Lesenswert?

Ich habe in C allerdings noch nie einen Vergleich mit TRUE oder FALSE 
gemacht. Beim if in C geht es einzig darum, ob das Ergebnis der Klammer 
0 oder ungleich 0 ist.

Bei anderen Sprachen kann es anders sein, in Swift z.B. darf der if 
Ausdruck nur vom Typ bool sein:
1
if a>b {
2
...
3
}
aber nicht
1
if a {
2
...
3
}

von Yalu X. (yalu) (Moderator)


Lesenswert?

Erwin D. schrieb:
> Meines Wissens nach, und ich habe es auch noch nicht anders gesehen,
> wird FALSE als 0 definiert und TRUE als !FALSE (und nicht als 1).

Wenn FALSE=0 ist, dann ist !FALSE = !0 = 1.

Eine Variable oder ein Ausdruck hat in C immer genau einen Wert und
nicht gleichzeitig mehrere, also bspw. alle Werte außer der 0.

Fritz G. schrieb:
> Es gibt allerdings in stdbool.h folgendes:

Genau dort sind true und false in C definiert (anders als in C++, wo
true und false vordefinierte Schlüsselwörter sind).

von Fritz G. (fritzg)


Lesenswert?

Yalu X. schrieb:
> Genau dort sind true und false in C definiert

Ja, aber nicht TRUE oder FALSE, das muss wo anders herkommen.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Philip K. schrieb:
> mh schrieb:
>> #define TRUE !0 ??? ;-)
>
> Das muss gar nicht ich definieren, das ist in C standardmässig so. ;)

Doch, daß musst du definieren, denn C (egal, in welcher Version) kennt 
weder das Keyword "TRUE" noch das Keyword "FALSE". Wer diese benutzen 
will, muß die definieren, und kann das beliebig tun, genauso wie foo 
oder bar.

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

Fritz G. schrieb:
> Yalu X. schrieb:
>> Genau dort sind true und false in C definiert
>
> Ja, aber nicht TRUE oder FALSE, das muss wo anders herkommen.

Ja, TRUE und FALSE sind nicht im C-Standard enthalten. Entweder der TO
hat sie selber definiert, oder er verwendet eine Bibliothek, in der sie
definiert sind (bspw. WinAPI).

von Rolf M. (rmagnus)


Lesenswert?

Erwin D. schrieb:
> Fritz G. schrieb:
>> if (data) ist was anderes als if (data == TRUE).
>>
>> Der erste Ausdruck ist wahr, wenn data ungleich Null ist, der zweite
>> Ausdruck ist wahr, wenn data genau eins ist.
>
> Das würde ja bedeuten, dass TRUE als 1 definiert ist. Meines Wissens
> nach, und ich habe es auch noch nicht anders gesehen, wird FALSE als 0
> definiert und TRUE als !FALSE (und nicht als 1).
> Damit wären die beiden Ausdrücke wieder identisch!

Nein, sind sie nicht! Rechne mal aus, was !0 ist. Dann wirst du 
feststellen: Es ist 1.
1
#define TRUE !FALSE
ist damit exakt gleichbedeutend mit
1
#define TRUE 1

Merke: data != 0 ist nicht das gleiche wie data == !0.

von Ingo L. (corrtexx)


Lesenswert?

Was hindert hier eigentlich daran diese Diskussion auf den Simulator zu 
bringen, dann hat man Gewissheit was rauskommt...

von Rolf M. (rmagnus)


Lesenswert?

Ingo L. schrieb:
> Was hindert hier eigentlich daran diese Diskussion auf den Simulator zu
> bringen, dann hat man Gewissheit was rauskommt...

Klar kann man vieles einfach ausprobieren, aber es gibt dann doch ein 
paar elementare Grundlagen, die man mal verstanden haben sollte, um 
nicht völlig im Nebel zu stochern.

von Ingo L. (corrtexx)


Lesenswert?

Rolf M. schrieb:
> Klar kann man vieles einfach ausprobieren, aber es gibt dann doch ein
> paar elementare Grundlagen, die man mal verstanden haben sollte, um
> nicht völlig im Nebel zu stochern.
Sicher, aber so wie das hier schon wieder ausartet wirds langsam albern 
;)

von Kai S. (zigzeg)


Lesenswert?

Michael schrieb:
> Kann man die 15 switch cases irgendwie anders ersetzen, durch einen
> verschachtelten Ausdruck ?

Michael schrieb:
> "data" hat eine Befehlsnummer drin stehen, anhand welcher
> dementsprechend ein bestimmtes Parameter übergeben werden soll ! "data"

Ich nehme also an, das die Befehlsnummern keine Luecken haben, sondern 1 
bis 16 sind. Dann kann man denn switch ganz einfach durch ein Array 
ersetzen:
1
const int ausdruecke[16] = { ausdruck1, audruck2, ausdruck3, ...};

Bei dem typ "int" musste ich raten - leider gibt Dein Pseudocode nicht 
mehr her.

Der Aufruf vereinfacht sich dann zu (da ja immer die selbe Funktion 
gerufen wird):
1
if ((data > 0) && (data <= 16)) {
2
    function(ausdruecke[data - 1]);
3
}

Und das ist ein ganzes Stueck kompakter !

von Default (Gast)


Lesenswert?

Mark B. schrieb:
> In einem switch...case hat man immer auch einen default-case. Damit
> kann man alle Werte erschlagen, die keine Aktion auslösen sollen.

Den Default-case kann man in diesem Fall dann ja auch gleich ganz 
weglassen.

von Mark B. (markbrandis)


Lesenswert?

Default schrieb:
> Mark B. schrieb:
>> In einem switch...case hat man immer auch einen default-case. Damit
>> kann man alle Werte erschlagen, die keine Aktion auslösen sollen.
>
> Den Default-case kann man in diesem Fall dann ja auch gleich ganz
> weglassen.

Es ist in aller Regel guter Programmierstil, den default-case nicht 
wegzulassen. Siehe z.B.:

http://stackoverflow.com/questions/4649423/should-switch-statements-always-contain-a-default-clause

von Daniel A. (daniel-a)


Lesenswert?

Mark B. schrieb:
> Es ist in aller Regel guter Programmierstil, den default-case nicht
> wegzulassen. Siehe z.B.:

Damit bin ich so Algemein nicht einverstanden. Ich verwende das Switch 
Case eigentlich immer mit enums, weil ich nicht mit magic numbers 
arbeite. Wenn ich kein Default case habe, warnt mich der Compiler, wenn 
ich einen Eintrag eines enums nicht im Switch berücksichtige. Ansonsten 
unterdrückt das Default case diese Warnung, der fall wird ja behandelt.

Ein default case sollte es nur geben, wenn man absichtlich viele Fälle 
nicht, oder gesondert behandelt. Allerdings spricht auch nicht viel 
dagegen, wenn man keine enums verwendet, oder den Warnlevel des 
Compilers sowiso nicht entsprechend hoch eingestellt hat.

: Bearbeitet durch User
von B. S. (bestucki)


Lesenswert?

Daniel A. schrieb:
> Wenn ich kein Default case habe, warnt mich der Compiler, wenn
> ich einen Eintrag eines enums nicht im Switch berücksichtige. Ansonsten
> unterdrückt das Default case diese Warnung, der fall wird ja behandelt.

GCC (4.9.3) warnt mich, wenn ich einen enum-Wert vergessen habe, obwohl 
ein default case vorhanden ist. GCC warnt mich auch, wenn ich kein 
default case vorhanden ist.


Daniel A. schrieb:
> Ich verwende das Switch
> Case eigentlich immer mit enums, weil ich nicht mit magic numbers
> arbeite.

Sehe ich auch so, die einzige Ausnahme sich chars, die lasse ich als 
magic numbers zu. In C++ arbeite ich auch gerne mit constexpr Variablen.

Den default case habe ich immer drin, auch wenn er leer ist. So weiss 
ich auch noch nach Jahren, dass das Absicht ist, in 90% der Fällen ist 
es das nicht.
1
default: /* Grund */ break;

von Jay (Gast)


Lesenswert?

Ingo L. schrieb:
>
1
>  if( data ){
2
>      switch(data){
3
>        case a: function(ausdruck_1); break;
4
>        case b: function(ausdruck_2); break;
5
>        default: break;
6
>      }
7
>  }
8
>
> Super kompakt und übersichtlich

Und ziemlich sinnlos. Es ist der Versuch einer manuellen Optimierung die 
man (A) schöner machen könnte, und (B) der Compiler bekommt sie von 
alleine vermutlich genauso gut hin.

(A) Wenn man ganz fest an die manuelle Optimierung glauben möchte:
1
    switch(data){
2
      case 0: // !data
3
              break;
4
      case a: function(ausdruck_1); break;
5
      case b: function(ausdruck_2); break;
6
      default: break;
7
    }

(B) Wenn der Compiler ganz in Ruhe sein Ding manchen soll:
1
    switch(data){
2
      case a: function(ausdruck_1); break;
3
      case b: function(ausdruck_2); break;
4
      default: break;
5
    }

Das default: schadet nichts. Auch das optimiert ein guter Compiler weg. 
Es nützt aber je nach Compiler um bei enums Warnungen zu vermeiden.

Wenn man die Kollegen verwirren möchte, kann man natürlich auch so etwas 
schreiben:

(A.2) Manuelle Optimierung zur Verwirrung:
1
    switch(data){
2
      case a: function(ausdruck_1); break;
3
      case b: function(ausdruck_2); break;
4
      case 0:
5
      default: break;
6
    }

von Daniel A. (daniel-a)


Lesenswert?

Be S. schrieb:
> GCC (4.9.3) warnt mich, wenn ich einen enum-Wert vergessen habe, obwohl
> ein default case vorhanden ist.

Cool, mit welcher Option kann ich das Aktivieren?
1
enum state {
2
  STATE_TEST_1,
3
  STATE_TEST_2
4
};
5
6
int main(){
7
  enum state s = 0;
8
  switch(s){ // complete
9
    case STATE_TEST_1: break;
10
    case STATE_TEST_2: break;
11
  }
12
  switch(s){ // default
13
    case STATE_TEST_1: break;
14
    default: break;
15
  }
16
  switch(s){ // one missing
17
    case STATE_TEST_1: break;
18
  }
19
}
1
abd@basalt ~ $ gcc -std=c99 -Wall -Wextra -pedantic test.c -o /dev/null
2
test.c: In function ‘main’:
3
test.c:16:3: warning: enumeration value ‘STATE_TEST_2’ not handled in switch [-Wswitch]
4
   switch(s){ // one missing
5
   ^

von B. S. (bestucki)


Lesenswert?

Daniel A. schrieb:
> Cool, mit welcher Option kann ich das Aktivieren?

-Wswitch-enum

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
> Warn whenever a switch statement has an index of enumerated type and
> lacks a case for one or more of the named codes of that enumeration.
> case labels outside the enumeration range also provoke warnings when
> this option is used. The only difference between -Wswitch and this option
> is that this option gives a warning about an omitted enumeration code
> even if there is a default label.

von Fritz G. (fritzg)


Lesenswert?

Im default case sollte man eine Fehlermeldung rausschreiben, 
schliesslich sollte der nicht vorkommen.

von Frickelfritze (Gast)


Lesenswert?

Michael schrieb:
> es ist so, dass ich aber 15 Varianten empfangen kann, daher wäre mein
> Switch Case 15 Optionen gross !
> Kann man die 15 switch cases irgendwie anders ersetzen, durch einen
> verschachtelten Ausdruck ?

Warum meldet hier niemand die Möglichkeit der Implementierung
eines Arrays von Funktionspointern?

Damit braucht jeder Aufruf eines Cases die genau gleiche
(geringe) Zeit, während bei einer switch/case Liste immer
sequentiell alles Mögliche (umsonst) abgefragt werden muss.

Bei grossen Listen lohnt sich das ....

von Jemand (Gast)


Lesenswert?

Frickelfritze schrieb:
> Warum meldet hier niemand die Möglichkeit der Implementierung
> eines Arrays von Funktionspointern?
>
> Damit braucht jeder Aufruf eines Cases die genau gleiche
> (geringe) Zeit, während bei einer switch/case Liste immer
> sequentiell alles Mögliche (umsonst) abgefragt werden muss.
>
> Bei grossen Listen lohnt sich das ....

Hast du das getestet oder ist das das übliche Misstrauen in den 
Compiler?

von Rolf M. (rmagnus)


Lesenswert?

Frickelfritze schrieb:
> Warum meldet hier niemand die Möglichkeit der Implementierung
> eines Arrays von Funktionspointern?

Weil das wenig Sinn ergibt, denn es soll ja immer die selbe Funktion 
aufgerufen werden, nur mit unterschiedlichen Parametern.

> Damit braucht jeder Aufruf eines Cases die genau gleiche
> (geringe) Zeit, während bei einer switch/case Liste immer
> sequentiell alles Mögliche (umsonst) abgefragt werden muss.

Wie kommst du denn darauf?

> Bei grossen Listen lohnt sich das ....

Genau deswegen machen Compiler das bei switch/case mit großen Listen 
üblicherweise per Sprungtabelle.

von Rene H. (Gast)


Lesenswert?

Frickelfritze schrieb:
> während bei einer switch/case Liste immer
> sequentiell alles Mögliche (umsonst) abgefragt werden muss.

Schau Dir mal den Assembler Output an :). Kompiler Bauer sind nicht 
blöd. Man kann solange optimieren wollen wie man will, der Kompiler 
macht das selbe draus. Es ist nur eine Frage der Lesbarkeit. Da steht 
switch/case zweifelsohne vor Funktionszeiger.

von Frickelfritze (Gast)


Lesenswert?

Rolf M. schrieb:
> Genau deswegen machen Compiler das bei switch/case mit großen Listen
> üblicherweise per Sprungtabelle.

Wenn "der" Compiler das so macht dann bin ich ja beruhigt,
nehme alles zurück und behaupte das Gegenteil.
Und ziehe den Schwanz ein und trotte davon ....

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Frickelfritze schrieb:
> Warum meldet hier niemand die Möglichkeit der Implementierung
> eines Arrays von Funktionspointern?

Ich zitier' mich mal:

Rufus Τ. F. schrieb:
> Die einzige Möglichkeit, hier etwas mehr Performance zu erzielen, setzt
> voraus, daß die Anzahl der Variationen und der Werteumfang lückenlos
> ist. Das wäre eine Tabelle aus Funktionspointern, die über Deine
> Variable indiziert und aufgerufen werden. Allerdings macht ein gut
> optimierender Compiler eh' so ziemlich dasselbe, so daß der
> Performancegewinn hier wirklich überschaubar sein dürfte.


Allerdings ist das komplett sinnlos, wenn eh' immer die gleiche Funktion 
nur mit unterschiedlichem Argument aufgerufen werden soll.

von Damme (Gast)


Lesenswert?

Michael schrieb:
> es ist so, dass ich aber 15 Varianten empfangen kann, daher wäre mein
> Switch Case 15 Optionen gross !
> Kann man die 15 switch cases irgendwie anders ersetzen, durch einen
> verschachtelten Ausdruck ?

Evtl. wären Funktionspointer in einer Tabelle eine Möglichkeit?

von Frickelfritze (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Allerdings ist das komplett sinnlos,

Ja das hatte ich für diesen speziellen Fall übersehen.

Rolf M. schrieb:
> Genau deswegen machen Compiler das bei switch/case mit großen Listen
> üblicherweise per Sprungtabelle.

Das funktioniert aber nicht wenn die switch/case Argumente "weit"
auseinanderliegen (also z.b. 100 Elemente im Bereich 0..65535), bzw
der Compiler würde ggf eine sehr lange Liste von Sprungbefehlen
anlegen deren Leerfelder aufs Default zeigen.

Oder gibt es da noch intelligentere Implementationen? Ich kann mir
das nicht vorstellen .... und bitte ggf um Aufklärung.

von Kaj (Gast)


Lesenswert?

Damme schrieb:
> Evtl. wären Funktionspointer in einer Tabelle eine Möglichkeit?

Rufus Τ. F. schrieb:
> Frickelfritze schrieb:
>> Warum meldet hier niemand die Möglichkeit der Implementierung
>> eines Arrays von Funktionspointern?
>
> Ich zitier' mich mal:
>
> Rufus Τ. F. schrieb:
>> Die einzige Möglichkeit, hier etwas mehr Performance zu erzielen, setzt
>> voraus, daß die Anzahl der Variationen und der Werteumfang lückenlos
>> ist. Das wäre eine Tabelle aus Funktionspointern, die über Deine
>> Variable indiziert und aufgerufen werden. Allerdings macht ein gut
>> optimierender Compiler eh' so ziemlich dasselbe, so daß der
>> Performancegewinn hier wirklich überschaubar sein dürfte.

von B. S. (bestucki)


Lesenswert?

Frickelfritze schrieb:
> Oder gibt es da noch intelligentere Implementationen? Ich kann mir
> das nicht vorstellen .... und bitte ggf um Aufklärung.

Ich habe auch schon Kombinationen aus Sprungtabelle und binärer Suche 
gesehen. Geht auch recht flott.

von Rolf M. (rmagnus)


Lesenswert?

Ich hab auch mal ein Gerücht gehört (weiß aber nicht ob's stimmt), dass 
es Compiler geben soll, die eine Hashfunktion für die Werte basteln und 
darüber den Index in de Sprungtabelle ermitteln, wenn die Werte zu weit 
auseinander liegen.

von B. S. (bestucki)


Lesenswert?

Rolf M. schrieb:
> Ich hab auch mal ein Gerücht gehört (weiß aber nicht ob's stimmt), dass
> es Compiler geben soll, die eine Hashfunktion für die Werte basteln und
> darüber den Index in de Sprungtabelle ermitteln, wenn die Werte zu weit
> auseinander liegen.

Wenn der Compiler eine Tabelle und/oder eine binäre Suche hinkriegt, 
sollte auch das möglich sein. Erkenne aber den Vorteil eines Hash nicht, 
da der Wertebereich eines case so oder so nicht grösser als 2^64 werden 
kann. Dann kann man auch gleich direkt nach dem gewünschten Wert suchen.

Beispiel Tabelle:
Beitrag "Re: switch case vs. Tabelle"

Beispiel binäre Suche:
Beitrag "Re: AVR-Programm muss effizienter werden"

von Jay (Gast)


Lesenswert?

Wer sehen möchte was der GCC mach: 
https://github.com/gcc-mirror/gcc/blob/edd716b6b1caa1a5cb320a8cd7f626f30198e098/gcc/stmt.c#L1114 
die expand_case und emit_case_... Funktionen.

von (prx) A. K. (prx)


Lesenswert?

Frickelfritze schrieb:
> Oder gibt es da noch intelligentere Implementationen? Ich kann mir
> das nicht vorstellen .... und bitte ggf um Aufklärung.

Ein cleverer Compiler wird die Liste der Werte analysieren und abhängig 
davon - und von Optimierung auf Tempo/Platz - eine sinnvolle Strategie 
wählen. Darunter dürfen auch welche sein, die krasse Fälle von 
Switch-Werten separat behandeln oder die Werte in besser optimierbare 
Untertabellen separieren. Der Phantasie sind da keine Grenzen gesetzt.

Bei ausreichend grosser Anzahl von nicht per Tabelle sinnvollen Werten 
wird jedoch gerne ein Vergleichsbaum gebildet. Bei Prozessoren mit 
effizientem Sprungverhalten ist das recht gut.

von Vlad T. (vlad_tepesch)


Lesenswert?

was genau ist denn das a in
1
case a:


Meinst du 'a', oder ist a auch irgend ein define?

Die Frage, ob es einen arithmetischen Zusammenhang gibt, den man 
ausnutzen könnte, wurde schon gestellt.

Michael schrieb:
> "data" und generierte_groesse haben einen nicht identischen Inhalt !

ist dafür keine befriedigende Antwort.

in deinem Beispiel
 (ich nehm jetzt einfach mal an, dass ein character im case gemeint war)
'a' -> 0xA
'b' -> 0xB
'c' -> 0xC
sind die Inhalte auch nicht gleich, ließen sich aber problemlos ableiten
(data - 'a' + 0xA)

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Michael schrieb:
> es ist so, dass ich aber 15 Varianten empfangen kann, daher wäre mein
> Switch Case 15 Optionen gross !
> Kann man die 15 switch cases irgendwie anders ersetzen, durch einen
> verschachtelten Ausdruck ?

Oh Mann, ich habe mir die Antworten (ehrlich geschrieben) nicht komplett 
durchgelesen - aber 15 mal den gleichen Ausdruck zu kopieren und 
anzupassen - das ist schon echt Arbeit.

Du tust mir leid, Du armer Troll :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.