Forum: Compiler & IDEs AVR Struct Zugriff


von Daniel (Gast)


Lesenswert?

Hallo Spezialisten,
ich habe leider nichts in der Suche gefunden || falsch gesucht.
Ich möchte anhand von Flags in einem Struct auf Unterroutinen 
verzweigen.
Das alles sollte etwa so aussehen:

struct {
        char bFlag1:1;
        char bFlag2:1;
        char bFlag3:1;
       } StatusFlags;

switch(StatusFlags)
 {
  case StatusFlags.bFlag1:  Routine1();
                            break;
  case StatusFlags.bFlag2:  Routine2();
                            break;
  case StatusFlags.bFlag2:  Routine3();
}

Die Flags sollen in Interruptroutinen gesetzt werden und im 
Hauptprogramm, wenn nötig, die entsprechende Routine angesprungen 
werden.

Des weiteren würde mich Interessieren wie man in einer for Schleife
Struct-Members anhand der Zählvariablen ansprechen kann.
Vielen Dank im vorraus für alle Tipps/Links.

von Floh (Gast)


Lesenswert?

Daniel schrieb:
> Die Flags sollen in Interruptroutinen gesetzt werden und im
> Hauptprogramm, wenn nötig, die entsprechende Routine angesprungen
> werden.

volatile

Daniel schrieb:
> Des weiteren würde mich Interessieren wie man in einer for Schleife
> Struct-Members anhand der Zählvariablen ansprechen kann.

sowas kann man z.B. mit unions machen, ist aber eigentlich nicht zu 
empfehlen :-)

von Floh (Gast)


Lesenswert?

Ach ja und die Verzweigung würd ich statt über switch über ein if-Block 
machen:

if(flag)
  ...
if(flag2)
  ...

...

von qwert (Gast)


Lesenswert?

Floh schrieb:
> Ach ja und die Verzweigung würd ich statt über switch über ein if-Block
> machen:

warum?

von Sven P. (Gast)


Lesenswert?

- Die case-Marken müssen Konstanten sein, daher haut das nicht hin.
- Wenn Bitvektoren im Spiel sind, würde ich von Unions ganz stark die 
Fingers weglassen :-}

von Floh (Gast)


Lesenswert?

Noch ne andere Idee, warum haust du nicht alle Flags in z.B. eine 
Int-Variable und belgst mit den Flags die einzelnen Bitstellen.
Dann sparste
1.Speicherplatz
2.Aufwand beim Auslesen
3.undefinierte Zustände

:-)

von Rolf Magnus (Gast)


Lesenswert?

qwert schrieb:
> Floh schrieb:
>> Ach ja und die Verzweigung würd ich statt über switch über ein if-Block
>> machen:
>
> warum?

Weil man man mit switch für verschiedene Werte einer Variable 
unterschiedliche Aktionen ausführen kann. Hier haben wir aber mehrere 
Variablen, bei denen man für jede eine Aktion hat, die ausgeführt werden 
soll, wenn sie nicht 0 ist.
Das heißt, daß zum einen mehrere Variablen vorhanden sind, was man mit 
switch einfach nicht abdecken kann, zum anderen können auch mehrere der 
Variablen gesetzt sein, so daß also mehrere Aktionen durchgeführt werden 
müssen.
Also ist der Weg, für jede Variable ein if zu verwenden, der richtige 
(und der übliche).

Daniel schrieb:
> Des weiteren würde mich Interessieren wie man in einer for Schleife
> Struct-Members anhand der Zählvariablen ansprechen kann.

Gar nicht.

von at (Gast)


Lesenswert?

gößere if else if blöcke sind aber ineffizient
wenn man ein 16bit flag "register" ist ein switch sinniger

wenn man hierrüber funktionen aufrufen will ..
könnte man sogar was lustiges mit funktionszeigern machen
dann brauch man nichtmal ein register

von Daniel (Gast)


Lesenswert?

Danke an alle für die angeregte Diskussion!!
Ich habe diese Aufgabe bis jetzt auch immer mit if() verzweigungen 
gelöst. Habe mir aber gedacht dass eine switch Verzweigung eleganter 
wäre. Es ist mir ja eigentlich klar dass über die Switch-Verzweigung 
nicht eine Verzweigung durch abhängigkeit von mehreren Variablen 
stattfinden kann. Aber ich dachte mir, es gebe evtl. einen Kniff über 
die Struct. Die Flags in einen int oder long zu speichern ist zwar 
einfach zu programmieren aber schlecht lesbar. if() verzweigungen sind 
leicht lesbar generieren aber einen grossen (Source) Code. Es gäbe noch 
die Möglichkeit des Zugriffs über Pointer aber dass scheint mir nicht so 
Wasserdicht...
Es wäre einfach schön gewesen wenn es einen Zugriff à la:
Structname.[Index]
gäbe!
Wenn noch jemand eine Idee hat währe ich natürlich weiterhin offen...

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:

> Wenn noch jemand eine Idee hat währe ich natürlich weiterhin offen...

Das übliche:
Ein C-Buch wäre nicht schlecht.
Dann brauchst du nicht raten.

von Rolf Magnus (Gast)


Lesenswert?

at schrieb:
> gößere if else if blöcke sind aber ineffizient
> wenn man ein 16bit flag "register" ist ein switch sinniger

Das gibt aber ein verdammt großes switch, wenn du jede beliebige 
Bitkombination damit erschlagen willst. Oder wie willst du den Fall 
behandeln, wenn mehrere Flags gleichzeitig gesetzt sind?

von gust (Gast)


Lesenswert?

Macht das überhaupt Sinn ?

Theoretisch kann jedes Flag = True sein, d.h. die es würde immer case 
Flag1 ausgeführt !!!

Die obige Strukte sollte ein enum statt eines Bitfieldes sein. Das würde 
die Variable StatusFlags immer einen eindeutigen Wert haben.

von Rolf Magnus (Gast)


Lesenswert?

gust schrieb:
> Macht das überhaupt Sinn ?

Daß mehrere Interrupt-Flags gleichzeitig gesetzt sein können? Ja. Daß 
man zu deren Abfrage switch/case verwendet? Nein.

> Die obige Strukte sollte ein enum statt eines Bitfieldes sein. Das würde
> die Variable StatusFlags immer einen eindeutigen Wert haben.

Es ist eher unsinnig, die Struktur an einen Sprachkonstrukt anzupassen, 
wenn sie dann nicht mehr zum eigentlichen Problem paßt.

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Floh schrieb:
> Noch ne andere Idee, warum haust du nicht alle Flags in z.B. eine
> Int-Variable und belgst mit den Flags die einzelnen Bitstellen.
> Dann sparste
> 1.Speicherplatz
> 2.Aufwand beim Auslesen
> 3.undefinierte Zustände

Das würde das C-Buch empfehlen, das Karl heinz Buchegger ansprach.
Bleibt noch das switch-case/if-else-Problem.

kann man die Unterroutinen nicht in die Interruptroutinen packen? Oder 
gibt das noch mehr Probleme?

von Rolf Magnus (Gast)


Lesenswert?

Silvan König schrieb:
> kann man die Unterroutinen nicht in die Interruptroutinen packen? Oder
> gibt das noch mehr Probleme?

Wenn sie sehr kurz bzw sehr timingkritisch ist, kann man das machen. 
Aber Interrupt-Routinen sollte man immer so kurz wie möglich halten. 
Meistens reicht es, in der ISR nur ein Flag zu setzen und in der 
Hauptschleife auszuwerten.

von Floh (Gast)


Lesenswert?

Daniel schrieb:
> Aber ich dachte mir, es gebe evtl. einen Kniff über
> die Struct. Die Flags in einen int oder long zu speichern ist zwar
> einfach zu programmieren aber schlecht lesbar. if() verzweigungen sind
> leicht lesbar generieren aber einen grossen (Source) Code.

Ja, zähl mal Zeilen :-)
#define FLAG1 (1<<0)
...
#define FLAG7 (1<<7)


if(flags & FLAG1)
  Unterprogramm1();
if(flags & FLAG2)
  Unterprogramm2();
if(flags & FLAG3)
  Unterprogramm3();
...

beim switch bräuchtest du für jeden Block noch ein break, das die 
Ausführung weiterer Unterprgoramme trotz gesetzen Flags unterbinden 
würde.
Schreibst du es nicht, werden alle folgenden Unterprogramme ausgeführt, 
ohne das Flag überhaupt zu prüfen.
:-)

von 78787 (Gast)


Lesenswert?

problem bei solch längeren if konstukten ist das jedesmal alle ifs 
durchlaufen werden bis es mal passt
ein switch case springt dort hin wo man es brauch
deswegen .. wenn mehr wie 5 if's dann lieber ein switch

man kann auch ein array mit funktionszeigern erstellen und das mit den 
funktionen füllen die man ausführen will


einzig für eine größere statemachine mit stringabfragen is mir noch nix 
eingefallen hier hilft anscheinend nur if(strncmp(..)==0) ...

von Floh (Gast)


Lesenswert?

78787 schrieb:
> problem bei solch längeren if konstukten ist das jedesmal alle ifs
> durchlaufen werden bis es mal passt

geht schneller als man denkt, ich denke pro nichtgesetzte Flag (also 
keine Ausführung), sinds 2 Takte pro Flag
Man kann ja in der Richtung auch optimieren, da die ersten 
Unterprogramme bei gleichzeitigen Flags zuerst aufgerufen werden.
Da kann man dann die meistbenötigten UPs vorne abfragen und die weniger 
relevanten UPs erst danach.


78787 schrieb:
> einzig für eine größere statemachine mit stringabfragen is mir noch nix
> eingefallen hier hilft anscheinend nur if(strncmp(..)==0) ...

kurze strings lassen sich zu einer Zahl zusammenbauen:
char c[4]={'2','a','5','s'};

long int t = (c[0]<<24)|(c[1]<<16)|(c[2]<<8)+c[3];
Das ganze kann dann in ein switch.
Über Sinn und Unsinn davon lässt sich streiten.:-)

von Sven P. (Gast)


Lesenswert?

78787 schrieb:
> problem bei solch längeren if konstukten ist das jedesmal alle ifs
> durchlaufen werden bis es mal passt
Das ist bei den meisten switch()-Anweisungen auch nicht anders.

Man könnte sich auch den Spaß machen und in ein C-Buch schauen. Da würde 
man auch ziemlich bald erkennen, dass der Ausdruck hinter einer 
case-Marke eine Konstante sein muss und die Idee mit der 
switch()-Anweisung und den Flags wie im Ursprungspost hinfällig ist.

> ein switch case springt dort hin wo man es brauch
> deswegen .. wenn mehr wie 5 if's dann lieber ein switch
Quark. Wenn es sich anhand der Werte nicht ergibt, eine Sprungtabelle 
o.Ä. aufzubauen, wirst du wieder eine schnöde Bedingungskette bekommen.


> einzig für eine größere statemachine mit stringabfragen is mir noch nix
> eingefallen hier hilft anscheinend nur if(strncmp(..)==0) ...
Das is aber traurig.
Denk mal drüber nach, die Zeichenketten sortiert in einem Vektor zu 
hinterlegen und dann mit einer binären Suche zu arbeiten.



Strukturelemente anhand eines Zählers ansprechen ginge, wenn du die 
(gleichartigen) Elemente in einen Vektor packst und über Indexkonstanten 
gehst. Wird auf dem AVR auch recht effizient, da der eine 
Adressierungsvariante mit Offset beherrscht.

Es spricht ansonsten auch überhaupt nichts gegen deine Bitvektoren, die 
sind weder langsamer, noch brauchen sie zwangsläufig mehr Speicher. Nur 
misshandeln (d.h., mit Unions oder Casts herumspielen) sollte man lieber 
nicht, da solcherlei Operationen nicht klar definiert sind.

Vielmehr sind läuft es im aktuellen avr-gcc auf denselben Assembler-Text 
hinaus. Wobei die Variante mit den Flags, die Floh oben vorgeschlagen 
hat, noch deutlich langsamer ist, da der gcc die Bitoperation 
standardmäßig auf einen Integer aufweitet (d.h., er rechnet mit 16 Bit), 
wohingegen der Bitvektor schnöde in einem 8-Bit-Feld vorgehalten wird.

Die folgenden beiden Varianten erzeugen bei Optimierung (egal worauf) 
identische Assemblies:
1
/* Variante 1 */
2
int main(void) {
3
        volatile struct {
4
                int a:1;
5
                int b:1;
6
                int c:1;
7
        } x;
8
9
10
        volatile int y;
11
        if (x.a)
12
                y = 1;
13
        else if (x.b)
14
                y = 2;
15
        else if (x.c)
16
                y = 3;
17
}
1
/* Variante 2 */
2
int main(void) {
3
        volatile unsigned char x;
4
5
        volatile int y;
6
7
        if (x & 1)
8
                y = 1;
9
        else if (x & 2)
10
                y = 2;
11
        else if (x & 4)
12
                y = 3;
13
}


Ohne Optimierung ist die Variante mit dem Bitvektor, wie oben schon 
beschrieben, effizienter.

von (prx) A. K. (prx)


Lesenswert?

Sven P. schrieb:

> Quark. Wenn es sich anhand der Werte nicht ergibt, eine Sprungtabelle
> o.Ä. aufzubauen, wirst du wieder eine schnöde Bedingungskette bekommen.

Ja, aber anders als du denkst. Wenn sie nicht trivial klein sind oder 
per Tabelle realisiert werden können, dann werden switch-Anweisungen 
gerne als Entscheidungsbaum implementiert. Auswand O(log(n)) statt O(n).

von (prx) A. K. (prx)


Lesenswert?

78787 schrieb:

> einzig für eine größere statemachine mit stringabfragen is mir noch nix
> eingefallen hier hilft anscheinend nur if(strncmp(..)==0) ...

Weshalb baut man eine Statemachine mit Strings als Zustand, wenn 
Zeiteffizienz ein Thema ist?

von 78787 (Gast)


Lesenswert?

das problem ist wenn ein angeschlossenes gerät strings aus einem pool 
liefert einem aber nur ein oaar bestimmte strings interessieren

man kann dann eine tabelle anlegen wo die entsprechenden hinterlegt sind
oder mit strncmp
beides läuft auf den vergleich einer zeichenkette hinnaus
ob man dies nun binär macht oder das dem strncmp überlässt ist fast das 
selbe
verglichen wird ein vorhandenes feld mit daten mit einem noch 
unbekanntem
feld mit länge x
das einzige was mir jetz noch einfällt ist das ganze nach werten zu 
bündeln
1
// alle wörter mit C am anfang
2
if( x[0] == 'C' ) 
3
{
4
  // 2ter buchstabe ist ein A
5
  if( x[1] == 'A' )
6
    ...
7
  // oder ein B
8
  else if( x[1] == 'B' )  
9
  {
10
     if( x[2] == 'D' )
11
        ...
12
     else if( x[2] == 'R' )  
13
  }
14
}
15
else if (x[0] == 'N')
16
{
17
.
18
.
19
.
20
}
lesbarkeit is fürn popo ..
würde aber auch funktionieren
ich schweife ab .. sry ...




nochmal zu if oder switch

ich hatte mal ein ähnliches problem
dort ist mir aufgefallen das ab 5-6 if's das kompilat größer wird als 
mit einem switch

wenn es immer nur eine funktion ist kann man das
auch mit einem void (*fp)(void) machen
auch ein array[x] PROGMEM ={ &funktion1 , &funktion2 ... } ist machbar
den index als wert oder als enum bauen fertig ist die lesbarkeit

es gibt viele wege nach Rom

von (prx) A. K. (prx)


Lesenswert?

Sowas lässt sich auch mittels lex/flex automatisieren.

von eklige Tunke (Gast)


Lesenswert?

78787 schrieb:
> das problem ist wenn ein angeschlossenes gerät strings aus einem pool
> liefert einem aber nur ein oaar bestimmte strings interessieren
Nichts für ungut, aber wo steht denn, dass das hier der Fall ist? Oder 
ist die Diskussion einfach nur mal wieder offtopic?

von Sven P. (Gast)


Lesenswert?

78787 schrieb:
> man kann dann eine tabelle anlegen wo die entsprechenden hinterlegt sind
> oder mit strncmp
> beides läuft auf den vergleich einer zeichenkette hinnaus
> ob man dies nun binär macht oder das dem strncmp überlässt ist fast das
> selbe
Oha. Bis auf dass die binäre Suche höchstens log(n) Vergleiche braucht, 
die normale Variante schlimmstenfalls n.
Da würde ich die binäre Suche ganz arg vorziehen...


> verglichen wird ein vorhandenes feld mit daten mit einem noch
> unbekanntem
> feld mit länge x
> das einzige was mir jetz noch einfällt ist das ganze nach werten zu
> bündeln
> [...]
> lesbarkeit is fürn popo ..
> würde aber auch funktionieren
> ich schweife ab .. sry ...
Gut erkannt, einen Schritt weiter und du hast die binäre Suche, genau, 
wie ich sie oben vorgeschlagen habe.


> nochmal zu if oder switch
>
> ich hatte mal ein ähnliches problem
> dort ist mir aufgefallen das ab 5-6 if's das kompilat größer wird als
> mit einem switch
Ich hatte irgendwann auch mal ein Radio, dabei ist mir aufgefallen, dass 
es draußen geregnet hat.


> wenn es immer nur eine funktion ist kann man das
> auch mit einem void (*fp)(void) machen
> auch ein array[x] PROGMEM ={ &funktion1 , &funktion2 ... } ist machbar
> den index als wert oder als enum bauen fertig ist die lesbarkeit
Oder ohne Index und mit binärer Suche. Spart einen Vektor und ist 
wunderbar lesbar.

bsearch() aus der Standardbibliothek ist in vielen Fällen eine prima 
Sache.

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.