Hallo,
folgendes Problem:
uint32_t cmd; //4 Bytes
cmd = LeseCmd(); //4 bytes
switch (cmd)
{
case "ABCD" //4 bytes, (ohne \0)
....;
}
Ich hätte hier gerne, dass beim kompilieren als Case-Vergleichswert der
entsprechende ASCII-Code 12345678 benutzt wird, ohne dass ich diesen per
Hand "ausrechnen" muss.
Für jeden dezenten Denkanstoß bin ich überaus dankbar.
PS:
'A' + ('B'<<8)+ ('C'<<16)+ ('D'<<24) geht, gefällt mir aber nicht.
Nein, jetz mal im Ernst:
Mir ist keine Präprozessor Anweisung bekannt die sowas leistet
und im case-Statement muss halt mal eine Konstante stehen
Aber machs halt so:
#define _ABCD ('A' + ('B'<<8)+ ('C'<<16)+ ('D'<<24))
#define _ABC1 ('A' + ('B'<<8)+ ('C'<<16)+ ('1'<<24))
#define _ABC2 ('A' + ('B'<<8)+ ('C'<<16)+ ('2'<<24))
#define _ABC3 ('A' + ('B'<<8)+ ('C'<<16)+ ('3'<<24))
.
.
.
uint32_t cmd; //4 Bytes
cmd = LeseCmd(); //4 bytes
switch (cmd)
{
case _ABCD: ....;
case _ABC1: ....;
case _ABC2: ....;
case _ABC3: ....;
....;
}
dann sieht dein Programm wenigstens schön aus
Viel Spass noch !!!
Peter Dannegger schrieb:> #define MK32(a,b,c,d) (((uint32_t)'a')<<24 | ((uint32_t)'b')<<16 | 'c'<<8 | 'd')> ...> case MK32(A,B,C,D):
Das ist mal schnell schön hingeschrieben, geht aber nicht !!!
Rolle schrieb:> Peter Dannegger schrieb:>> #define MK32(a,b,c,d) (((uint32_t)'a')<<24 | ((uint32_t)'b')<<16 | 'c'<<8 |
'd')
>> ...>> case MK32(A,B,C,D):>>> Das ist mal schnell schön hingeschrieben, geht aber nicht !!!>>>> Beitrag melden | Bearbeiten | Löschen |
geht bei gcc, OK, aber nicht allen Compilern
Funktioniert bei mir auch mit GCC nicht. Also ich glaube auch dass die
Textersetzung mittels Makro nicht erlaubt ist und bei der case anweisung
nur ganzzahlige Konstanten stehen dürfen.
-> Was spricht gegen einen if-Rechen
Mfg Michi
Michael Rathmair schrieb:> Funktioniert bei mir auch mit GCC nicht.
geht nocht oder compiliert nicht? Wenn ja welche Fehlermeldung
> Also ich glaube auch dass die> Textersetzung mittels Makro nicht erlaubt ist und bei der case anweisung> nur ganzzahlige Konstanten stehen dürfen.
die Preprozessor ist es egal wo er etwas ersetzt, er kennt kein switch.
nach dem Preprozessor steht ja dort eine Konstante.
Oh sorry, sorry sorry für die Übereile.
Man sollte mal richtig tippen können.
Michael Rathmair schrieb:> #define MAKEK32(a,b,c,d) (((unsigned int)'a')<<24 || ((unsigned int)'b')<<16 ||
'c'<<8 || 'd')
muss natürlich
#define MAKE32(a,b,c,d) (((unsigned int)'a')<<24 || ((unsigned
int)'b')<<16 || 'c'<<8 || 'd')
sein.
Michael Rathmair schrieb:> -> Was spricht gegen einen if-Rechen
Beim einen werden Zahlen verarbeitet, beim anderen knechtet er mit
Strings. Das ist beim PC relativ egal, ein posierlicher µC hat daran
verdammt viel zu tun.
Egal ob PC oder nicht, solange es ohne String-geklöppel geht, würde ich
es ohne machen.
Im übrigen sollte die Textersetzung der GCC gar nicht mitbekommen? Der
Präprozessor kommt doch vor dem Compiler.
Michael Rathmair schrieb:> A. K. schrieb:>> Klar doch. (x || 'A') ist immer 1.>> So gesehen schon dann funktioniert die Lösung aber doch nicht richtig> ?????
Wo ist denn der Unterschied zwischen '|' und '||'?
oder
Wo ist denn der Unterschied zwischen '&' und '&&'?
Lest mal ein C Buch und findet heraus was der Unterschied zwischen einem
'|' und einem '||' ist.
Ich würde im Zweifel aber auch die if then else if ... Kette bevorzugen.
Peter Dannegger schrieb:> Stimmt, die ' sind falsch, es geht nur so:#define MK32(a,b,c,d)
(((uint32_t)a)<<24 | ((uint32_t)b)<<16 | c<<8 | d)
> ...> case MK32('A','B','C','D'):
Das sieht gut aus !
ole schrieb:> Wo ist denn der Unterschied zwischen '|' und '||'?> oder> Wo ist denn der Unterschied zwischen '&' und '&&'?
Oh je nochmal sorry. Klar weiß ich dass das '||' eine ein logische und
das '|' eine bitweise Operation ist und in diesem Fall eine bitweise
Operation richtig ist.
Michael Rathmair schrieb:> Oh je nochmal sorry. Klar weiß ich dass das '||' eine ein logische und> das '|' eine bitweise Operation ist
Wobei du nicht der erste warst dem der Fehler passiert ist, das war wohl
Falk, aber dem müssen wir nicht den Unterschied erklären :-)
Macht halt jeder mal einen Fehler, vor allem wenn man wie bei so Fragen
mal schnell 'trocken' codiert, also ohne das dann zu compilieren
und/oder auszuprobieren.
@ U.R. Schmitt (Gast)
>> Oh je nochmal sorry. Klar weiß ich dass das '||' eine ein logische und>> das '|' eine bitweise Operation ist>Wobei du nicht der erste warst dem der Fehler passiert ist, das war wohl>Falk, aber dem müssen wir nicht den Unterschied erklären :-)
Ohhhh vor den kopfklatsch.
Da hatte ich wohl einen Dreher im Hirn. Und ich hab mich gestern ne
halbe Stunde gefragt, warum bei meiner Simulation Unsinn rauskommt.
Naja.
MFG
Falk
Das gefällt mir so ganz gut (natürlich inkl. Anführungszeichen an der
richtigen Stelle ;-), aber mir ist noch etwas eingefallen:
Das ganze soll im Sinne von Modem-AT-Befehlen arbeiten. Wenn ich nun
aber ca. 100 Befehle bearbeite, wird immer die komplette 4-Byte Variable
verglichen. Ich weiß zwar nicht, was ein "if-Rechen" ist, aber ich
glaube, dass damit ein Zweig im Sinne eines Stammbaumes gemeint ist.
Jedenfalls führt letzteres zu einer enorm schnelleren Verarbeitung, da
zB. viele Befehle mit 's' bzw. 'g' (set/get) beginnen:
1
switch(cmd>>24){
2
3
case'A':
4
5
switch(cmd>>16){
6
7
case'C':printf("AC");
8
break;
9
case'D':printf("AD");
10
break;
11
default:printf("Ax");
12
break;
13
}
14
15
case'B':
16
17
switch(cmd>>16){
18
19
case'C':printf("BC");
20
break;
21
case'D':printf("BD");
22
break;
23
default:printf("Bx");
24
break;
25
}
26
default:printf("xx");
27
break;
28
}
Ich hatte gehofft, dass der super gcc auch dieses herausfindet und somit
den ersten Buchstaben nur einmal vergleicht usw., tut er aber nicht. Es
bleibt mir also wohl doch nur die Möglichkeit, die Befehle aufzudröseln.
Allen Beteiligten vielen Dank für die Anregungen.
Johannes K. schrieb:> Ich hatte gehofft, dass der super gcc auch dieses herausfindet und somit> den ersten Buchstaben nur einmal vergleicht usw., tut er aber nicht. Es> bleibt mir also wohl doch nur die Möglichkeit, die Befehle aufzudröseln.
Du kannst dir auch mal flex anschauen:
de.wikipedia.org/wiki/Lex_(Informatik)
en.wikipedia.org/wiki/Flex_lexical_analyser
Johannes K. schrieb:> den ersten Buchstaben nur einmal vergleicht usw., tut er aber nicht.
Mir ist zwar nicht klar, was genau du damit meinst, aber bei deinem
Beispiel fehlen
1) die breaks hinter den "Sub-Switches"
2) das Ausmaskieren eines Zeichens im switch ((cmd>>16) ist nicht das
zweite Zeichen, sondern die ersten beiden)
Zusatz zu 2): wenn du jeweils nach einzelnen Buchstaben vorgehst, wozu
dann diese vorher überhaupt zu einem uin32_t kombinieren?
Stefan Ernst schrieb:
> Mir ist zwar nicht klar, was genau du damit meinst, aber bei deinem> Beispiel fehlen> 1) die breaks hinter den "Sub-Switches"
Da hast du natürlich Recht.
> 2) das Ausmaskieren eines Zeichens im switch ((cmd>>16) ist nicht das> zweite Zeichen, sondern die ersten beiden)
Ich meine, dass er immer nur 1 Byte benutzt, da ich ja mit nur 1
vergleiche. Daher verwendet der Compiler dann doch das zweite.
>> Zusatz zu 2): wenn du jeweils nach einzelnen Buchstaben vorgehst, wozu> dann diese vorher überhaupt zu einem uin32_t kombinieren?
Mache ich dann natürlich nicht, war jetzt im Beispiel einfacher.
Johannes K. schrieb:> Ich meine, dass er immer nur 1 Byte benutzt, da ich ja mit nur 1> vergleiche. Daher verwendet der Compiler dann doch das zweite.
Da meinst du falsch. Du vergleichst keine einzelnen Bytes, sondern
komplette Zahlen.
1
uint16_ta=0xabcd;
2
uint8_tb=0xcd;
3
4
if(a==b)...
Der Vergleich ist natürlich false, und nicht etwa (wie du meinst) true,
nur weil der untere Teil von a mit b übereinstimmt.
Stefan Ernst schrieb:> Da meinst du falsch. Du vergleichst keine einzelnen Bytes, sondern> komplette Zahlen.
Ok, hast natürlich wieder Recht. Ich würde also noch nach uint8_t casten
müssen, wenn ich es so verwenden wollte. Richtig?
Meine Lösung sieht nun so aus (Auch, wenn mir Vergleiche mit "SE", "SD",
usw. lieber gewesen wäre):
A. K. schrieb:> Du kannst dir auch mal flex anschauen:> de.wikipedia.org/wiki/Lex_(Informatik)> en.wikipedia.org/wiki/Flex_lexical_analyser
Was willst du mir damit sagen?
Dass der GCC es doch erkennt und alle 'Axxx' zusammenfast und alle
'Bxxx'?
Johannes K. schrieb:> Was willst du mir damit sagen?> Dass der GCC es doch erkennt und alle 'Axxx' zusammenfast und alle> 'Bxxx'?
Lex/Flex sind Codegeneratoren, denen man ein spezielle Quellfile
vorsetzt und die daraus C Code produzieren. Das Ergebnis ist eine
C-Funktion, die nicht mehr einzelne Zeichen zurück gibt, sondern fertige
Tokens die für eine beliebige Anzahl Zeichen eines bestimmten Musters
stehen. Und das recht zeiteffizient.
Aus der Lex-Beschreibung
1
"ABCD"{return1;}
2
"xyz"{return2;}
3
[0-9]+{yylval=atoi(yytext);return3;}
4
.{crash("Trottel!");}
wird Code erzeugt, der aus einem irgendwoher sequentiell gelesenen
Zeichenstrom beim String "ABCD" den Wert 1 zurück gibt, bei "xyz" 2, bei
jeder nicht negativen dezimalen Ganzzahl 3 (und deren Wert sich in der
Variable yylval befindet). Die letzte Zeile ist sowas wie das default:
vom switch.
Das sind gern benutze Tools, um Programmier- oder Kommandosprachen in
ihre lexikalischen Einzelteile wie Schlüsselworte, Zahlen, Strings und
Namen zu zerlegen.