Hallo, kann mir jemand auf die Sprünge helfen? Habe im Forum nach "volatile" gesucht, aber über die folgende Warnung hat noch niemand berichtet (vielleicht ist der Grund auch trivial??). In einer RTC-Funktion wird ein Zeit/Datum-Array "TimeDate" erhöht; die RTC-Funktion wird von einem Timer-Interrupt aufgerufen (im Minutentakt, entsprechend heruntergeteilt). Früher hatte ich das "volatile" bei "TimeDate"-Deklaration vergessen, da war noch alles okay, hat auch funktioniert (vielleicht auch nur "zufällig" - okay, bei Computern gibt es keine Zufälle). Dann erkannte ich das Versäumnis, daß Variablen, die in Interrupt-Funktionen verändert werden, als volatile deklariert werden müssen. Habe dann das "volatile" hinuzgefügt; das Programm funktioniert natürlich immer noch, aber nun erscheinen Warnungen bei den "memcpy"-Funktionen (gibt noch mehr, als im Code-Fragment steht): ../main.c:1936: warning: passing arg 2 of `memcpy' discards qualifiers from pointer target type Code-Fragment: #define TIMEDATENUMBYTES 5 /* Zahl der Bytes der TimeDate-Arrays */ volatile uint8_t TimeDate[TIMEDATENUMBYTES]; /* hh:mm dd:mm:yy */ ... void ZeitDatumAnzeigen(void) { uint8_t timedate[TIMEDATENUMBYTES]; /* lokale TimeDate-Variable */ ... sreg=SREG; /* Globale Zeit lokal kopieren */ cli(); memcpy(timedate,TimeDate,sizeof(timedate)); SREG=sreg; fprintf_P(&DevLCD,PSTR("%02u:%02u %02u.%02u.%02u"), timedate[0],timedate[1],timedate[2],timedate[3],timedate[4]); ... } Wahrscheinlich erscheinen die Warnungen im Zusammenhang mit der Verwendung von Zeigern ("TimeDate" ist ja ein Zeiger) und der Deklaration von "memcpy", das ja nicht mit "volatile" deklariert ist. Die Warnung stört mich, obwohl alles funktioniert. Weiß jemand, wie man sie wegbekommen kann? Danke. Günter
Mit einem Typecast: memcpy(timedate, (void *) TimeDate, sizeof (timedate));
Du bist da in einer Zwickmühle. Die Warnung besagt logisch gedacht, dass das volatile von memcpy() nicht beachtet wird. Und das ist eine gute Warnung. memcpy() nimmt beim Kopieren keine Rücksicht darauf, dass sich der Inhalt der Quelle während der Kopieraktion ändern kann. memcpy setzt sogar voraus, dass sich die Quelle nicht ändert (Deklaration mit const void *). Du berücksichtigst das Verhalten von memcpy() bereits, indem du mit cli() die Interrupts sperrst, so dass sich der Inhalt von TimeDate nicht mehr ändern kann. Um die Warnung an dieser Stelle wegzubekommen, finde ich es legitim einen cast einzufügen.
Wenn man allerdings die Warnung erfolgreich mit dem Cast los wird und der Code danach trotzdem noch funktioniert, ist das eigentlich das beste Zeichen, dass es in diesem Falle des "volatile"s gar nicht bedurft hätte. > memcpy setzt sogar voraus, dass sich die Quelle nicht ändert > (Deklaration mit const void *). Nein, diese Deklaration besagt, dass es selbst das Objekt, auf das der Zeiger zeigt, nicht ändern möchte.
> Dann erkannte ich das Versäumnis, daß Variablen, die in > Interrupt-Funktionen verändert werden, als volatile deklariert werden > müssen. Und auch das stimmt so nicht. Von müssen kann keine Rede sein. Das volatile ist im Grunde nur für den wichtig, der diese Variable auch benutzt. Wie zb hier: while( j == 5 ) ; ist j nicht volatile deklariert, so geht der Compiler davon aus, dass j sich in der Schleife nicht ändern kann und optimiert entsprechend. Eine volatile Deklaration hingegen sagt dem Compiler: "Du weist auch nicht alles über diese Variable. Die Variable kann sich ändern, ohne dass es in dem Code-Stück, das du überblicken kannst, ersichtlich wäre." Das macht volatile und das hat erstmal nichts mit Interrupts an sich zu tun.
@Jörg: "Wenn man allerdings die Warnung erfolgreich mit dem Cast los wird und der Code danach trotzdem noch funktioniert, ist das eigentlich das beste Zeichen, dass es in diesem Falle des "volatile"s gar nicht bedurft hätte." Dieser Logik folgend wird man, wenn man mit eher einfach gestrickten Compilern arbeitet, nie volatile benötigen. Und sich fuchsteufelswild über einen völlig unbrauchbaren GCC ärgern, der das halt etwas anders sieht. Nein, so läuft das nicht. Array-Zugriffe werden in der Praxis oft kein volatile benötigen. Aber irgendwann vielleicht schon. Also muss es sein, auch dann wenn sich erst einmal nichts ändert.
> Array-Zugriffe werden in der Praxis oft kein > volatile benötigen. Aber irgendwann vielleicht schon. Nein, brauchen sie nicht. Das ist nur die Kurzfassung, für die Formulierung der Langfassung, warum sie (*) kein "volatile" brauchen, würde ich vermutlich eine halbe Stunde benötigen, um die entsprechenden Stellen des Standards herauszusuchen und zu zitieren. Wenn man das Beschreiben eines Arrays zwischen zwei Threads (also z. B. zwischen Interrupt- und Hauptkontext) synchronisieren will, sollte man das über eine (dann wirklich "volatile" qualifizierte) Semaphore-Variable machen. Du kannst dir ziemlich sicher sein, dass der GCC an dieser Stelle bereits alles ausnutzt, was der Standard gestattet. (*) In der Regel -- du kannst natürlich pathologische Fälle provozieren, wenn du sowas hast wie
1 | uint8_t myarr[42]; |
2 | |
3 | ...
|
4 | |
5 | while (myarr[23] != 5) |
6 | /* wait until it's 5 */ ; |
Danke an alle - Problem ist gelöst mit dem "(void *)" (hätte ich selber drauf kommen können, aber manchmal hat man ja Tomaten auf den Augen). Danke auch für den Hinweis von Jörg - ja, man kann hier "volatile" bestimmt weglassen; aber der Klarheit wegen lasse ich's doch drin (es wird nicht schaden). Günter
Was meinst Du denn damit? Pessimistischer Code? Davon habe ich noch nie gehört ...
,,pessimieren'' ist einfach das Gegenteil von ,,optimieren''. ;-)
Ach so, Wortspiel. Okay. Ich überleg's mir nochmal, ob ich das volatile entferne.
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.