Hallo zusammen!
Teste gerade ein LCD-Menü für einen AVR (für AVR-GCC) vorab auf dem PC
unter Linux (ebenfalls mit GCC). Die Menü-Daten liegen in einem Array
die Größe des Array soll der Preprozessor dem #define size zuweisen. Bis
hier funktioniert noch alles.
Die Größe size wird dann zum Vergleich für die Begrenzung der Variablen
LCDstate benutzt. Das funktioniert nicht sauber, wenn der vom
Preprozessor zugewiesene Wert zum Vergleich benutzt wird.
Wird in der Vergleichsfunktion dagegen eine manuell definierte Konstante
oder eine Variable benutzt, funktioniert alles tadellos!
Hier der Codeausschnitt:
1
#define NR_ENTRIES(x) (sizeof(x)/sizeof(*x))
2
#define size NR_ENTRIES( mainMenu ), mainMenu
3
// size wird richtig zugewiesen mit 14
4
#define size1 14 // manuelle Zuweisung zum debug
5
6
uint8_tKEYstate=0;
7
8
intmain(void){
9
10
while((c=getch())!='\n'){
11
if(KEYstate!=KEY_CL){// hat sich der Tastenstatus geändert?
Das Verhalten tritt nur auf, beim Vergleich die Größe size mit Zuweisung
über #define size NR_ENTRIES( mainMenu ), mainMenu und dass, obwohl die
Zuweisung mit 14 richtig erfolgt. Folgende Änderungen im Code ergeben
verschiedene Ergebnisse.
// Hier erhalte ich einen Vergleich mit 14 anstatt 13
if (LCDstate == 255) {LCDstate = size-1;}
// Hier erhalte ich einen Vergleich mit 13, richtig!
if (LCDstate == 255) {LCDstate = -1+size;}
// LCDstate ist danach immer 0 (size über Preprozessor zugewiesen)
if (LCDstate >= size) {LCDstate = 0;}
// die Funktion arbeitet richtig
if (LCDstate >= 14) {LCDstate = 0;}
// die Funktion arbeitet richtig (size1 manuell zugewiesen)
if (LCDstate >= size1) {LCDstate = 0;}
Dieses Verhalten kann ich mir nicht erklären. Könnte das ein Bug im GCC
sein, oder habe ich hier einen Fehler der mir nicht einleuchten will?
Ich sehe keine Deklaration für die Variable LCDstate, bitte poste alle
relevanten Codeausschnitte, diese Variable ist relevant für das Problem,
also ist es auch sinnvoll ihre Deklaration mal zu sehen. Oder bin ich
blind?
Sowohl KEYstate alsd auch LCDState scheinen von Außerhalb der
while-schleife manipuliert zu werden, evtl durch einen Interrupt. Wenn
Du solche Variablen in einer while() auf Veränderung pollst dann denkt
der Compiler sie können sich niemals ändern und optimiert sie kurzerhand
weg!
Daher ist es zwingend daß Du alle Variablen mit denen Du dergleichen
Dinge tust als volatile deklarierst!
Vielen Dank für die Antworten!
@g457
Ich weiß leider nicht, welchen Kommaoperator du ansprichst.
@Bernd K.
Du bist nicht blind! Habe ich vergessen hinzuschreiben. Richtig ist:
uint8_t KEYstate=0, LCDstate=0;
Beide Variablen werden nicht ausserhalb der Schleife manipuliert. Zur
Erfassung vom KEYstate liegt noch folgender Code innerhalb der Schleife,
den ich zur Übersichtlichkeit weggelassen hatte, da es m. e. in meinem
Fall nicht relevant ist.
KEYstate = KEY_CL;
switch (c) {
case KEY_DOWN:
KEYstate=KEY_RETURN;
break;
case KEY_UP:
KEYstate=KEY_RETURN;
break;
case KEY_LEFT:
KEYstate=KEY_MINUS;
break;
case KEY_RIGHT:
KEYstate = KEY_PLUS;
break
}
Habe KEYstate und LCDstate jetzt als volatile uint8_t deklariert. Das
hat aber keine Änderung ergeben.
@Tom
Tom schrieb:> #define size NR_ENTRIES( mainMenu ), mainMenu> Warum baut man sich solche Fallen ein?>>>>LCDstate = size-1;> wird damit besonders lustig.
Das verstehe ich nicht.
1. Es stammt nicht von mir sondern einen der Moderatoren hier und ich
bin davon ausgeganen, dass der Code erprobt ist.
2. Der Preprozessor läuft doch vor dem Compiler. Bis der Compiler sein
Werk beginnt, sollte es doch genau so sein wie ein
#define size 14
und das ist wie eine Konstante. Wieso ist also:
LCDstate = 14-1; besonders lustig und stellt eine Falle dar?
@Rolf Magnus
Habe beide Vergleiche durch Makros ersetzt.
if (LCDstate == 255) {LCDstate = (sizeof(mainMenu)/sizeof(*mainMenu)),
mainMenu-1;}
liefert den falschen Vergleich mit 14
if (LCDstate >= (sizeof(mainMenu)/sizeof(*mainMenu)), mainMenu)
{LCDstate = 0 ;}
liefert LCDstate 0
@Alle
Was mir vor allem nicht einleuchten will: warum funktioniert:
if (LCDstate == 255) {LCDstate = -1+size;} richtig und
if (LCDstate == 255) {LCDstate = size-1;} nicht richtig?
Wo ist da der Unterschied?
Warum funktioniert es mit der manuellen Zuweisung
#define size1 14
richtig, obwohl size ja auch richtig ermittelt wurde, was ich ja mit
write(LCD, " LCDstate: %i, Size: %i",LCDstate, size);
überprüfen kann?
HerbertK schrieb:> if (LCDstate == 255) {LCDstate = -1+size;} richtig und
Führt zu LCDstate = mainMenu;
> if (LCDstate == 255) {LCDstate = size-1;} nicht richtig?
Führt zu LCDstate = mainMenu-1;
a = b,c-1 führt zu a = c-1, wobei von b nur Seiteneffekte bleiben.
a = -1+b,c führt zu a = c und das -1+ ist für den Allerwertesten.
Anders wärs bei a = (b,c)-1 vs a = -1+(b,c).
Was das eigentlich soll entzieht sich freilich meiner Erkenntnis.
HerbertK schrieb:> Warum funktioniert es mit der manuellen Zuweisung
Weil NUR Dein Makro NR_ENTRIES(x) in der Zuweisung angewendet wird und
das -1 auf MainMenu angewendet wird, dies jedoch NICHT LCDstate
zugewiesen wird, da es NACH dem Komma steht!!!!
LCDstate = -1+size funktioniert nur, weil LCDstate zuerst mit -1 geladen
wird und dann durch den Makro NR_ENTRIES(x) die 14 aufaddiert werden.
Ändere die Definition von size bzgl. dem Komma und alles wird gut!
A. K. schrieb:> HerbertK schrieb:>> if (LCDstate == 255) {LCDstate = -1+size;} richtig und>> Führt zu LCDstate = mainMenu;
Nein.
> a = b,c-1 führt zu a = c-1, wobei von b nur Seiteneffekte bleiben.
Nein, denn es wird aufgelöst als:
(a = b), c-1
Die Zuweisung bindet stärker als das Komma.
> a = -1+b,c führt zu a = c und das -1+ ist für den Allerwertesten.
Nein, es führt zu a = -1+b.
HerbertK schrieb:> @g457> Ich weiß leider nicht, welchen Kommaoperator du ansprichst.
Na der, den du verwendet hast:
HerbertK schrieb:
1
#define size NR_ENTRIES( mainMenu ), mainMenu
2
^
3
DiesesKomma
> 1. Es stammt nicht von mir sondern einen der Moderatoren hier und ich> bin davon ausgeganen, dass der Code erprobt ist.
Dann hast du ihn vermutlich falsch übertragen, denn er egibt keinen
Sinn.
> 2. Der Preprozessor läuft doch vor dem Compiler. Bis der Compiler sein> Werk beginnt, sollte es doch genau so sein wie ein>> #define size 14>> und das ist wie eine Konstante.
Das ist aber nicht das, was bei der Ersetzung dieses Makros rauskommt.
> Wieso ist also:>> LCDstate = 14-1; besonders lustig und stellt eine Falle dar?
Weil da nicht "14-1" rauskommt, sondern "14, mainMenu-1".
> @Alle> Was mir vor allem nicht einleuchten will: warum funktioniert:>> if (LCDstate == 255) {LCDstate = -1+size;} richtig und
hier ist sie rechts vom Komma.
> Warum funktioniert es mit der manuellen Zuweisung>> #define size1 14>> richtig, obwohl size ja auch richtig ermittelt wurde, was ich ja mit>> write(LCD, " LCDstate: %i, Size: %i",LCDstate, size);>> überprüfen kann?
Es würde genau die gleichen Fehler aufweisen, wenn du dort auch den
Komma-Operator verwendest, wie bei der anderen Variante:
1
#define size1 14, mainMenu
Wirf bei deinem Makro size einfach das Komma und alles danach raus. Dann
funktionert es:
Bernd K. schrieb:> irgendeine obskure Syntax die zwar niemand verwendet aber trotzdem> irgendeinen Sinn aus grauer Vorzeit hat?
Als es noch keine Inline-Funktionen gab nutzte man der Effizienz halber
in Makros, die in funktionalem Kontext genutzt wurden, wahre Kunstwerke,
gebildet aus ?: und , Operatoren.
g457 schrieb:> Nicht wirklich. Mach mal den Kommaoperator raus, der ist (nicht nur> hier) böse.Rolf Magnus schrieb:> Wirf bei deinem Makro size einfach das Komma und alles danach raus. Dann> funktionert es: #define size NR_ENTRIES( mainMenu )
Das war es!
Vielen Dank