Forum: Compiler & IDEs Warnung bei Verwendung von volatile


von TechInfo (Gast)


Lesenswert?

Hallo,

ich habe ein char-Array als volatile deklariert, da ich sowohl in der 
ISR als auch in der main darauf zugreife (ein Zeichenpuffer für den 
UART-Eingang).

Nun gibt mir der Compiler immer dann eine Warnung, wenn ich mit dem 
Array arbeiten möchte, z.B.:

warning: passing arg 1 of `strncat' discards qualifiers from pointer 
target type

Wahrscheinlich, weil er Zeiger auf char erwartet, aber volatile Zeiger 
auf char bekommt.

Kann ich das einfach übergehen?

von Karl H. (kbuchegg)


Lesenswert?

TechInfo wrote:
> Hallo,
>
> ich habe ein char-Array als volatile deklariert, da ich sowohl in der
> ISR als auch in der main darauf zugreife (ein Zeichenpuffer für den
> UART-Eingang).
>
> Nun gibt mir der Compiler immer dann eine Warnung, wenn ich mit dem
> Array arbeiten möchte, z.B.:
>
> warning: passing arg 1 of `strncat' discards qualifiers from pointer
> target type
>
> Wahrscheinlich, weil er Zeiger auf char erwartet, aber volatile Zeiger
> auf char bekommt.
>
> Kann ich das einfach übergehen?

Ja kannst du.

Du kannst in diesem Fall aber auch einfach das volatile vom
Array wegnehmen. Die Fälle um die es bei volatile geht,
sind mit Arrays beim gcc nicht realisierbar, sodass es kein
Problem ist, Arrays nicht volatile zu machen.


von TechInfo (Gast)


Lesenswert?

Danke. Könntest du das noch weiter ausführen?

Optimiert der Compiler Arrays nicht?

von Karl H. (kbuchegg)


Lesenswert?

Worum gehts den bei 'volatile'.

Volatile sagt dem Compiler, dass er keine Optimierungen
auf der Variablen machen soll.
Das ist wichtig in Fällen wie:

uint8_t flag

ISR( ... )
{
  flag = 1;

int main()
{

  ...

  flag = 0;

  while( flag == 0 ) {
    ...
  }
}

Ein optimierender Compiler kann (und wird) drauf kommen, dass
seiner Ansicht nach es in main() keine Möglichkeit gibt, dass
flag jemals etwas anderes als 0 sein kann. Daher kann er zu
dem Schluss kommen, das es keine Möglichkeit gibt die Schleife
jemals zu verlassen und er daher die Abfrage ob flag immer
noch 0 ist rauswerfen kann. Seiner Ansicht nach ändert sich
dadurch nichts an der Programmlogik.
Das es einen 2-ten, asynchronen Pfad gibt, in dem flag zu 1
werden kann, kriegt er einfach nicht mit.

Ein anderes Scenario wäre, wenn der Compiler beschliesst, dass
er flag in ein Register lädt und dort auch belässt. Dadurch
muss bei der Abfrage von flag dessen Wert nicht jedesmal aus
dem Speicher geholt werden, sondern liegt schon in einem Register
vor.

Mit volatile kann das behoben werden: volatile verbietet jegliche
Optimierung auf einer Variablen, sodass:
 * der Compiler die Schleifenbedingung da oben auf jeden Fall
   immer neu auswerten muss
 * die Variable nicht in einem Register zwischengespeichert
   werden darf.

Nur: Speziell für die Zwischenspeicherung in einem Register
muss der Datentyp natürlich auch dafür geeignet sein. Ein
Array ist das aber ganz sicher nicht, sodass keine Gefahr
besteht, dass gcc hier eine Registeroptimierung vornehmen
wird.

Hmm. Das hindert aber die Datenflussanalyse nicht festzustellen,
dass isch das Array nicht im Schleifendurchlauf ändert. ....

Ich zieh meine Aussage zurück. Mach das Array volatile.

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


Lesenswert?

Das Array volatile machen, hilft ja auch nicht, da er es eben an
Funktionen übergeben will, für die es sowieso nicht volatile
wäre.  Da es trotzdem noch funktioniert, kann man sich das dann
auch gleich klemmen.

Solange man das Array nur im Ganzen nimmt, ist das OK.  Was man
natürlich nicht machen kann ist:
1
uint8_t somearray[32];
2
3
ISR(FOO_vect)
4
{
5
  somearray[0] = 1;
6
  ...
7
}
8
9
int
10
main(void)
11
{
12
  for (;;) {
13
    while (somearray[0] != 1)
14
      /* warten */ ;
15
    somearray[0] = 0;
16
    ...
17
  }
18
}

Was aber geht ist:
1
volatile uint8_t flag;
2
uint8_t somearray[32];
3
4
ISR(FOO_vect)
5
{
6
  somearray[...] = ...;
7
  flag = 1;
8
}
9
10
int
11
main(void)
12
{
13
  for (;;) {
14
    while (flag != 1)
15
      /* warten */ ;
16
    flag = 0;
17
    tuwas(somearray);
18
    ...
19
  }
20
}

In diesem Falle sorgt die volatile-Variable flag für die
Synchronisation, der Compiler hat keinen Grund, somearray[] innerhalb
von main() überhaupt zu bewerten.  Das tut er erst innerhalb von
tuwas(), und an dieser Stelle ist die ISR verlassen und damit auch der
Inhalt des Arrays wieder stabil.

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.