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 :-)
- 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
intmain(void){
3
volatilestruct{
4
inta:1;
5
intb:1;
6
intc:1;
7
}x;
8
9
10
volatileinty;
11
if(x.a)
12
y=1;
13
elseif(x.b)
14
y=2;
15
elseif(x.c)
16
y=3;
17
}
1
/* Variante 2 */
2
intmain(void){
3
volatileunsignedcharx;
4
5
volatileinty;
6
7
if(x&1)
8
y=1;
9
elseif(x&2)
10
y=2;
11
elseif(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
elseif(x[1]=='B')
9
{
10
if(x[2]=='D')
11
...
12
elseif(x[2]=='R')
13
}
14
}
15
elseif(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.