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.
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 :-)
Ach ja und die Verzweigung würd ich statt über switch über ein if-Block machen: if(flag) ... if(flag2) ... ...
Floh schrieb: > Ach ja und die Verzweigung würd ich statt über switch über ein if-Block > machen: warum?
- 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 :-}
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 :-)
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.
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
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...
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.
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?
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.
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.
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?
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.
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. :-)
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) ...
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.:-)
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.
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).
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?
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
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.