Forum: Compiler & IDEs Warnung bei volatile (AVR-GCC)


von Günter R. (galileo14)


Lesenswert?

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

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Mit einem Typecast:

  memcpy(timedate, (void *) TimeDate, sizeof (timedate));

von Stefan (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Karl heinz B. (kbucheg)


Lesenswert?

> 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.

von A.K. (Gast)


Lesenswert?

@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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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 */ ;

von Günter R. (galileo14)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> (es wird nicht schaden).

Es ,,pessimiert'' den Code.

von Günter R. (galileo14)


Lesenswert?

Was meinst Du denn damit? Pessimistischer Code? Davon habe ich noch nie 
gehört ...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

,,pessimieren'' ist einfach das Gegenteil von ,,optimieren''. ;-)

von Günter R. (galileo14)


Lesenswert?

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
Noch kein Account? Hier anmelden.