Forum: Compiler & IDEs switch case vs. Tabelle


von Kapitän Nuss (Gast)


Lesenswert?

Hallo,
ich habe hier ein Programmfragment in C
Ist es nicht besser das als Tabelle zu machen, anstelle von switch/case?
1
        parameter1 = 0;
2
  if(~GP0DAT & (1 << 1)) parameter1 += 1;
3
  if(~GP4DAT & (1 << 6)) parameter1 += 2;
4
  if(~GP0DAT & (1 << 6)) parameter1 += 4;
5
  if(~GP3DAT & (1 << 0)) parameter1 += 8;
6
7
  switch(parameter1)
8
  {
9
    case  0: I_mul =        1; break;
10
    case  1: I_mul =        2; break;
11
    case  2: I_mul =        5; break;
12
    case  3: I_mul =       10; break;
13
    case  4: I_mul =       20; break;
14
    case  5: I_mul =       50; break;
15
    case  6: I_mul =      100; break;
16
    case  7: I_mul =      200; break;
17
    case  8: I_mul =      500; break;
18
    case  9: I_mul =     1000; break;
19
    case 10: I_mul =     2000; break;
20
    case 11: I_mul =     5000; break;
21
    case 12: I_mul =    10000; break;
22
    case 13: I_mul =    20000; break;
23
    case 14: I_mul =    50000; break;
24
    case 15: I_mul =   100000; break;
25
    default: I_mul = 0; // um Compiler Warnung los zu werden!
26
  }
Wie am besten?

von (prx) A. K. (prx)


Lesenswert?

Bei wie hier sequentiellen Werten ist eine Tabelle vorzuziehen.

von Karl H. (kbuchegg)


Lesenswert?

Kapitän Nuss schrieb:
> Hallo,
> ich habe hier ein Programmfragment in C
> Ist es nicht besser das als Tabelle zu machen, anstelle von switch/case?

Mit ein bischen Glück macht der Compiler sowieso daraus eine Tabelle.

Ich würds allerdings trotzdem händisch in Tabellenform überführen. Schon 
alleine deswegen, weil das den Code nicht so in die Länge zieht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Kapitän Nuss schrieb:

> Ist es nicht besser das als Tabelle zu machen, anstelle von switch/case?
1
$ cat foo.c
2
#include <stdint.h>
3
4
uint32_t x(uint8_t parameter1)
5
{
6
uint32_t I_mul;
7
switch(parameter1)
8
  {
9
    case  0: I_mul =        1; break;
10
    case  1: I_mul =        2; break;
11
    case  2: I_mul =        5; break;
12
    case  3: I_mul =       10; break;
13
    case  4: I_mul =       20; break;
14
    case  5: I_mul =       50; break;
15
    case  6: I_mul =      100; break;
16
    case  7: I_mul =      200; break;
17
    case  8: I_mul =      500; break;
18
    case  9: I_mul =     1000; break;
19
    case 10: I_mul =     2000; break;
20
    case 11: I_mul =     5000; break;
21
    case 12: I_mul =    10000; break;
22
    case 13: I_mul =    20000; break;
23
    case 14: I_mul =    50000; break;
24
    case 15: I_mul =   100000; break;
25
    default: I_mul = 0; // um Compiler Warnung los zu werden!
26
  }
27
return I_mul;
28
}
29
$ avr-gcc -mmcu=avr5 -Os -S foo.c
30
$ cat foo.s
31
        .file   "foo.c"
32
__SP_H__ = 0x3e
33
__SP_L__ = 0x3d
34
__SREG__ = 0x3f
35
__tmp_reg__ = 0
36
__zero_reg__ = 1
37
        .text
38
.global x
39
        .type   x, @function
40
x:
41
        push r16
42
        push r17
43
/* prologue: function */
44
/* frame size = 0 */
45
/* stack size = 2 */
46
.L__stack_usage = 2
47
        cpi r24,lo8(16)
48
        brsh .L3
49
        ldi r25,0
50
        movw r30,r24
51
        lsl r30
52
        rol r31
53
        add r30,r24
54
        adc r31,r25
55
        subi r30,lo8(-(CSWTCH.2))
56
        sbci r31,hi8(-(CSWTCH.2))
57
        ld  r24,Z
58
        ldd r25,Z+1
59
        ldd r26,Z+2
60
        movw r16,r24
61
        mov r18,r26
62
        ldi r19,0
63
        rjmp .L2
64
.L3:
65
        ldi r16,0
66
        ldi r17,0
67
        movw r18,r16
68
.L2:
69
        movw r22,r16
70
        movw r24,r18
71
/* epilogue start */
72
        pop r17
73
        pop r16
74
        ret
75
        .size   x, .-x
76
        .section        .rodata
77
        .type   CSWTCH.2, @object
78
        .size   CSWTCH.2, 48
79
CSWTCH.2:
80
        .byte   1
81
        .byte   0
82
        .byte   0
83
        .byte   2
84
        .byte   0
85
        .byte   0
86
        .byte   5
87
        .byte   0
88
        .byte   0
89
        .byte   10
90
        .byte   0
91
        .byte   0
92
        .byte   20
93
        .byte   0
94
        .byte   0
95
        .byte   50
96
        .byte   0
97
        .byte   0
98
        .byte   100
99
        .byte   0
100
        .byte   0
101
        .byte   -56
102
        .byte   0
103
        .byte   0
104
        .byte   -12
105
        .byte   1
106
        .byte   0
107
        .byte   -24
108
        .byte   3
109
        .byte   0
110
        .byte   -48
111
        .byte   7
112
        .byte   0
113
        .byte   -120
114
        .byte   19
115
        .byte   0
116
        .byte   16
117
        .byte   39
118
        .byte   0
119
        .byte   32
120
        .byte   78
121
        .byte   0
122
        .byte   80
123
        .byte   -61
124
        .byte   0
125
        .byte   -96
126
        .byte   -122
127
        .byte   1
128
        .ident  "GCC: (GNU) 4.7.2"
129
.global __do_copy_data

Der GCC 4.7.2 scheint da deiner Meinung zu sein. :-)

von Kapitän Nuss (Gast)


Lesenswert?

ich hab es mal als Tabelle geschrieben:
1
  {
2
    unsigned char mouse_piano = 0;
3
    const unsigned long int mul_tab[16]=
4
    {1,2,5,10,20,50,100,200,500,1000,2000,5000,10000,20000,50000,100000};
5
    if(~GP0DAT & (1 << 1)) mouse_piano += 1;
6
    if(~GP4DAT & (1 << 6)) mouse_piano += 2;
7
    if(~GP0DAT & (1 << 6)) mouse_piano += 4;
8
    if(~GP3DAT & (1 << 0)) mouse_piano += 8;
9
    I_mul = mul_tab[mouse_piano];
10
  }
So besser?

von Kapitän Nuss (Gast)


Lesenswert?

@Autor: Jörg Wunsch (dl8dtl)

Wow, der GCC 4.7.2 ist ja voll schlau.
Besten Dank dafür!

Aber Sorry, ich hätte erwähnen müssen, das mein µC ein ADuC7126 und der 
Compiler der Keil Realview??? ist.
Mein Fehler.

Ich denke, ich lasse das jetzt so als Tabelle.

Kann man (nur so interessenhalber) das noch anders programmieren?
Diese Tabelle wird ja nur einmal lokal benötigt.

von Mac (Gast)


Lesenswert?

Da du mouse_piano aus Zweierpotenzen abfragst, kannst du die Werte für 
mouse_piano auch direkt aus den abgefragten Bits bestimmen.

z.b. ist (GP0DAT & (1<<1)) enweder 2 oder 0. Bei 2 addierst du aber 1 
zu mouse_piano, also:
1
   mouse_piano += (~GP0DAT & (1 << 1))>>1;

Wenn man alle vier Fälle zusammenfasst ergibt sich:
1
    mouse_piano=((~GP0DAT & (1 << 1))>>1)
2
               +((~GP4DAT & (1 << 6))>>5)
3
               +((~GP0DAT & (1 << 6))>>4)
4
               +((~GP3DAT & (1 << 0))<<3);

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Kapitän Nuss schrieb:
> Aber Sorry, ich hätte erwähnen müssen, das mein µC ein ADuC7126 und der
> Compiler der Keil Realview??? ist.

Tja, du schreibst aber gerade im GCC-Forum ...

von Karl H. (kbuchegg)


Lesenswert?

Kapitän Nuss schrieb:

> Kann man (nur so interessenhalber) das noch anders programmieren?

Natürlich.

Schau dir die case Werte an. Die sind schön regelmässig aufsteigend. 
Schau dir die zugewiesenen Werte an. Auch dort ist so etwas wie ein 
regelmässiges Muster zu erkennen.
Das legt es nahe, dass es eine Formel geben muss, die das eine in das 
andere überführt.

Sieht man sich die Zahlen mal genauer an, dann entdeckt man schnell eine 
Art 3-er Gruppierung. Zugewiesen werden im Grunde immer nur die 3 Zahlen 
1, 2 und 5 mit jeweils einem anderen Faktor einer Zehnerpotenz.

nimmt man also den Rest von parameter1 bei der Division durch 3, dann 
sagt einem dieser Rest, ob man jetzt mit 1, 2, oder 5 zu hantieren hat. 
Und das Divisionsergebnis selber sagt einem, wieviele 0-en noch an diese 
1, 2 oder 5 anzuhängen sind.

Aus dieser Beobachtung jetzt eine Idee für ein algorithmisches Verfahren 
(zb auch unter Zuhilfenahme 1 oder 2 Tabellen) herzuleiten, ist dann 
nicht mehr weiter schwer.

Nur lohnt sich das in diesem Fall bei 15 Zahlen nicht. Anders sieht es 
aus, wenn man eine wirklich große Tabelle hätte, die auch regelmässig 
gewartet werden muss. Dann wird eine einzige Tabelle mit vielen 
Einträgen schnell unübersichtlich.

von Kapitän Nuss (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Tja, du schreibst aber gerade im GCC-Forum ...

sorry stimmt, war aber keine böse Absicht, nur Gedankenlosigkeit.

Schade das wir hier kein Keil-Realview-Forum haben!

von Karl H. (kbuchegg)


Lesenswert?

Kapitän Nuss schrieb:
> Jörg Wunsch schrieb:
>> Tja, du schreibst aber gerade im GCC-Forum ...
>
> sorry stimmt, war aber keine böse Absicht, nur Gedankenlosigkeit.
>
> Schade das wir hier kein Keil-Realview-Forum haben!

Schreib einfach dazu, dass du den Keil Compiler benutzt.
Abgesehen davon wird das gcc Forum sowieso immer mehr zu einem "C 
Fragen, die auf einem µC auftreten" Forum. (Im Gegensatz zu all dem 
PC-spezifischen Dingen, die gehören ins PC-Forum).
Die Moderatoren hatten das mal untereinander diskutiert und ich glaube 
mich zu erinnern, dass wir darüber soweit Konsensus hatten, das gcc 
Forum mehr als "C Forum für den AVR" anzusehen.

In diesem Sinne hat Jörg schon recht: gcc ist die Default-Annahme. Wenn 
die nicht stimmt, sollte man das erwähnen.

von Roland H. (batchman)


Lesenswert?

Kapitän Nuss schrieb:
> Ist es nicht besser das als Tabelle zu machen, anstelle von switch/case?

Es gibt Fälle, in welchem switch/case besser abschneiden kann:

- Im Falle von switch/case mit einem const Parameter optimiert der 
Compiler den Rest u. U. weg (evtl. auch nur bei C++).

- Ebenso im Falle von templates, in welchem das switch/case vom 
Template-Parameter abhängt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:
> Bei wie hier sequentiellen Werten ist eine Tabelle vorzuziehen.

Das kann GCC selba mit -ftree-switch-conversion, automatisch aktiviert 
ab -O<guckst-du-in-doku>.

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> Das kann GCC selba mit -ftree-switch-conversion, automatisch aktiviert
> ab -O<guckst-du-in-doku>.

Yep, siehe oben. Tabelle ist jedenfalls nicht schlechter, bei sicherlich 
vielen Compilern aber besser. Wie hält sein Keil das?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:
> Johann L. schrieb:
>> Das kann GCC selba mit -ftree-switch-conversion, automatisch aktiviert
>> ab -O<guckst-du-in-doku>.
>
> Yep, siehe oben.

Ja, lesen hilft ;-)

> Tabelle ist jedenfalls nicht schlechter, bei sicherlich
> vielen Compilern aber besser.

Bei avr-gcc liegt die Tabelle jedenfalls im RAM (.rodata), siehe auch 
PR49857:

http://gcc.gnu.org/PR49857

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.