mikrocontroller.net

Forum: Compiler & IDEs Warnung bei Verwendung von volatile


Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.


Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke. Könntest du das noch weiter ausführen?

Optimiert der Compiler Arrays nicht?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
uint8_t somearray[32];

ISR(FOO_vect)
{
  somearray[0] = 1;
  ...
}

int
main(void)
{
  for (;;) {
    while (somearray[0] != 1)
      /* warten */ ;
    somearray[0] = 0;
    ...
  }
}

Was aber geht ist:
volatile uint8_t flag;
uint8_t somearray[32];

ISR(FOO_vect)
{
  somearray[...] = ...;
  flag = 1;
}

int
main(void)
{
  for (;;) {
    while (flag != 1)
      /* warten */ ;
    flag = 0;
    tuwas(somearray);
    ...
  }
}

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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.