Forum: Mikrocontroller und Digitale Elektronik Verständnisfrage zu "volatile"


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Tom (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo liebe Gemeinde,

ich hatte eigentlich gedacht, dass ich verstehe was "volatile" macht - 
aber hier verstehe ich es nicht:

Code:
void test()
{
  volatile int8_t rotarySteps1 = 0;

  while( 1 )
  {
    _delay_ms(1000);
    rotarySteps1 =  1;

    uart_putInt(rotarySteps1, true);
    uart_putInt(100 + rotarySteps1, true);
    uart_putInt(100 + rotarySteps1, true);
    uart_putInt(100 + rotarySteps1, true);

  }
}


Der Output ist:

1
1
101
132
132
32
96
196
196
196
32
96
196
196
196
32
96

Versteht einer von euch warum?

(ohne volatile läuft der output wie erwartet)

(auf die rotarySteps1 variable wird nirgends anders zugegriffen)

Falls wichtig, die  Funktion uart_putInt macht folgendes:

int uart_putInt(uint8_t i, bool newLine)
{
  char stringNumber[3];
  itoa(i, stringNumber, 10 );
        uart_putString (stringNumber, newLine);
  return 0;
}

Falls ich die 100+ entferne  - dann kommen nur "1" Werte (wie erwartet)

Danke!

von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
Bei einer lokalen Variabel ist volatile sinnlos. Damit kann man 
bestenfalls dem Compiler die Optimierung verbieten und in einigen 
Degug-Situationen was reißen. volatile ist nur für globale Variablen 
sinnvoll, auf welche an mehreren Stellen zugegriffen werden kann. Also 
Variablen für ISR-Kommunikation oder Hardwareregister.

von Matthias L. (lippy)


Bewertung
0 lesenswert
nicht lesenswert
>volatile int8_t rotarySteps1 = 0;
Wertebereich: -128 .. +127

uint8_t i
Wertebereich:    0 .. +255

Hier solltest Du zumindest für rodentliche Verhältnisse sorgen.

von Mario M. (thelonging)


Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> uart_putInt(100 + rotarySteps1, true);
>

> int uart_putInt(uint8_t i, bool newLine)
> {
>   char stringNumber[3];
>   itoa(i, stringNumber, 10 );

Buffer overflow?

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
Irgendwelche Warnungen bei maximalem Warnlevel?

von Stephan (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> char stringNumber[3];

Was passiert, wenn Du da ein char[5] draus machst? char[3] ist ja immer 
zu klein bei i>99.

von Tom (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dirk B. schrieb:
> Irgendwelche Warnungen bei maximalem Warnlevel?

Nein - leider nicht :-/

Kann es sein, dass itoa im Inneren die Variable überschreibt statt 
kopiert?

von Tom (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Falk B. schrieb:
> Bei einer lokalen Variabel ist volatile sinnlos. Damit kann man
> bestenfalls dem Compiler die Optimierung verbieten und in einigen
> Degug-Situationen was reißen. volatile ist nur für globale Variablen
> sinnvoll, auf welche an mehreren Stellen zugegriffen werden kann. Also
> Variablen für ISR-Kommunikation oder Hardwareregister.

Hallo Danke Falk,

klar  - ich will die Funktion von volatile verstehen (debuggen eines 
größeren Codes) - daher hier einen sehr komprimierten Code, der das 
Problem bereits zeigt.

von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> Kann es sein, dass itoa im Inneren die Variable überschreibt statt
> kopiert?

Der Fehler liegt vor der Tastatur. Deiner Tastatur.

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> Kann es sein, dass itoa im Inneren die Variable überschreibt statt
> kopiert?

Nein.
Denn C kennt nur Call by Value.
Aber es kann ub geben, wenn Strings zu klein bemessen sind.

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> Kann es sein, dass itoa im Inneren die Variable überschreibt statt
> kopiert?

Ja, irgendwas wird überschrieben.

itoa überschreibt das, was hinter deinem char stringNumber[3] steht, 
wenn die Zahl einen String ergibt, der länger als 2 Zeichen ist. Also ab 
100 aufwärts. Das letzte Zeichen eines Arrays, das als String verwendet 
wird, muß immer 0x00 sein. Das ist die Terminierung. Bis 99 geht alles 
gut und ab 100 fängt dein Programm an zu spinnen, da jetzt in das vierte 
Byte des Arrays, für das gar kein Platz reserviert ist, die Terminierung 
reingeschrieben wird.

Das wollte dir Stephan auch schon mitteilen, hast du nur nicht kapiert:

Stephan schrieb:
> Was passiert, wenn Du da ein char[5] draus machst? char[3] ist ja immer
> zu klein bei i>99.

Also char stringNumber[4] reicht auch für eine maximal dreistellige 
Zahl.

: Bearbeitet durch User
von Stephan (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich hatte das (kommende) Vorzeichen schon berücksichtigt;)

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
0 lesenswert
nicht lesenswert
Damit liegst du natürlich richtig.

von W.S. (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Tom schrieb:
> Versteht einer von euch warum?

Klar, selbstverständlich verstehe ich das.
Aber erstmal zu der Unsitte, die leider weit verbreitet ist:
1
volatile int8_t rotarySteps1 = 0;
2
...

Was erwartest du bei so einer lokalen variable auf dem Stack?
Ich empfinde es als weitaus anständiger und lesbarer, wenn man das so 
schreibt:
1
int8_t rotarySteps1;
2
3
rotarySteps1 = 0;
4
...

Und warum?
Weil man eigentlich will, daß die Variable auf dem Stack am 
Funktionsbeginn auf Null gesetzt wird. Das schreibt man besser 
ausführlich, wenn auch dies ein paar Tastendrücke mehr mit sich bringt. 
Dafür würdest jedoch auch DU es sogleich richtig lesen.

So und nun zu 'volatile':
Sowas benutzt man lediglich, um sicherzustellen, daß eine globale 
Variable bei mehrfacher Benutzung in einer Funktion auch wirklich 
jedesmal neu geladen wird und nicht durch einen Rest in irgendeinem 
CPU-Register lokal ersetzt wird. Es könnte ja sein, daß in der 
Zwischenzeit diese Variable durch jemand anderes (z.B. einen Interrupt 
oder eine andere grad aufgerufene Funktion oder gar die schiere Hardware 
des Chips) verändert wird und man das ohne jedesmaliges tatsächliches 
Laden gar nicht mitkriegen würde.

Das 'volatile' ist eine C-spezifische Krücke, die dem geschilderten 
Zweck dient, da C kein wirkliches Modulsystem und eigentlich auch keine 
Hardware-Register kennt. Gäbe es Ausdrucksmittel in C, anhand derer der 
Compiler feststellen könnte, ob eine Variable von anderer Seite 
überhaupt veränderlich sein kann, während die aktuelle Funktion am 
Laufen ist oder nicht, dann könnte man sich das volatile sparen. Aber 
so, wie das in C ist, muß man eben manuell vor derartige Variablen ein 
volatile davorschreiben.

Und vor lokale Variablen, die auf dem Stack liegen, ist das volatile 
eben verkehrt. Sowas bringt den Compiler bestenfalls durcheinander: die 
Variable darf er nicht auf dem Stack zwischenspeichern, jedoch liegt sie 
ja bereits auf dem Stack.

W.S.

von Dirk B. (dirkb2)


Bewertung
5 lesenswert
nicht lesenswert
W.S. schrieb:
> Ich empfinde es als weitaus anständiger und lesbarer, wenn man das so
> schreibt:

Ich nicht.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
4 lesenswert
nicht lesenswert
Dirk B. schrieb:
> W.S. schrieb:
>> Ich empfinde es als weitaus anständiger und lesbarer, wenn man das so
>> schreibt:
>
> Ich nicht.

Ich auch nicht.
Aber wir wissen ja, dass W.S. keine Ahnung von C hat.

von MaWin (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Tom schrieb:
> void test()
> {
>   volatile int8_t rotarySteps1 = 0;
1
void test()
2
{
3
   static volatile int8_t rotarySteps1 = 0;

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
0 lesenswert
nicht lesenswert
Ergänzung:

Mw E. schrieb:
> Aber wir wissen ja, dass W.S. keine Ahnung von C hat.
Was man hierran merkt:

W.S. schrieb:
> Und vor lokale Variablen, die auf dem Stack liegen, ist das volatile
> eben verkehrt. Sowas bringt den Compiler bestenfalls durcheinander: die
> Variable darf er nicht auf dem Stack zwischenspeichern, jedoch liegt sie
> ja bereits auf dem Stack.

volatile sagt dem Compiler/Optimierer auch, dass er Zugriffe nicht 
vertauschen darf.
Wäre manchmal etwas blöd bei einem Peripherieregister.
Bei einer normalen variable ist das egal.
Daher macht volatile auf einer STack Variable nunmal Sinn.
Aber W.S. ist nur mal wieder zu blöd!

von W.S. (Gast)


Bewertung
-4 lesenswert
nicht lesenswert
Dirk B. schrieb:
> Ich nicht.

Das ist dann dein Problem und das derjenigen, die deine Quellen lesen 
müssen.

Und jetzt erklär mir mal, was du dir unter

volatile int8_t rotarySteps1 = 0;

als tatsächliche Funktionalität des vom Compiler erzeugten Codes 
vorstellen würdest.

Wie du siehst, hat der TO genau damit seine Probleme, die er garantiert 
nicht hätte, wenn er die Zuweisung der 0 an die Variable separat 
hingeschrieben und nicht in eine Zeile zusammengezogen hätte.

Dann hätte sein Programm sogar trotz des fehlbesetzten volatile 
funktioniert. Viel wahrscheinlicher hätte er jedoch selbst den Unsinn 
erkannt und es richtig gemacht.

Es gibt ne Menge Leute, ie bei Vergleichen in C grundsätzlich die 
Konstante zuerst schreiben:
nicht if (A==3)
sondern if (3==A)
eben um zu vermeiden, daß man per Schussel dor eine Zuweisung 
produziert. Sowas ist eine Sache der inneren Disziplin - an der es hier 
jedoch vielen Leuten mangelt. Die wollen lieber ihre Genialität 
kultivieren.

W.S.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
3 lesenswert
nicht lesenswert
W.S. schrieb:
> Sowas ist eine Sache der inneren Disziplin - an der es hier
> jedoch vielen Leuten mangelt. Die wollen lieber ihre Genialität
> kultivieren.

Ja so wie du bei deiner Debugger Verteufelung versuchst "genial" 
dazustehen.
Nur hat eine schlaue Person mit Debugger einen fiesen Bug in deinem USB 
Stack entdeckt.
Also belehre andere Leute nicht über Disziplin wenn du nichtmal deine 
eigenen auferlegten Tugenden erfüllen kannst.
Du machst dich dazu nur noch mehr zur Lachnummer!

von Dirk B. (dirkb2)


Bewertung
3 lesenswert
nicht lesenswert
W.S. schrieb:
> Das ist dann dein Problem und das derjenigen, die deine Quellen lesen
> müssen.

Du hast vor allem die Initialisierung von der Definition getrennt.

Das soll übersichtlicher sein? du musst zweimal die Variable suchen.
Mir tun deine Leser leid,

von Yalu X. (yalu) (Moderator)


Bewertung
3 lesenswert
nicht lesenswert
W.S. schrieb:
> Was erwartest du bei so einer lokalen variable auf dem Stack?
> Ich empfinde es als weitaus anständiger und lesbarer, wenn man das so
> schreibt:int8_t rotarySteps1;
>
> rotarySteps1 = 0;

Unsinn.

W.S. schrieb:
> Sowas benutzt man lediglich, um sicherzustellen, daß eine globale
> Variable bei mehrfacher Benutzung in einer Funktion auch wirklich
> jedesmal neu geladen wird und nicht durch einen Rest in irgendeinem
> CPU-Register lokal ersetzt wird.

Der Gebrauch von volatile muss sich nicht auf globale Variablen
beschränken.

> Aber so, wie das in C ist, muß man eben manuell vor derartige
> Variablen ein volatile davorschreiben.

Das ist in deinem heißgeliebten Delphi und Free Pascal nicht anders, nur
dass es dort das volatile noch nicht so lange gibt.

> Und vor lokale Variablen, die auf dem Stack liegen, ist das volatile
> eben verkehrt. Sowas bringt den Compiler bestenfalls durcheinander: die
> Variable darf er nicht auf dem Stack zwischenspeichern, jedoch liegt sie
> ja bereits auf dem Stack.

Unsinn.

W.S. schrieb:
> Wie du siehst, hat der TO genau damit seine Probleme, die er garantiert
> nicht hätte, wenn er die Zuweisung der 0 an die Variable separat
> hingeschrieben und nicht in eine Zeile zusammengezogen hätte.

Unsinn.

> Es gibt ne Menge Leute, ie bei Vergleichen in C grundsätzlich die
> Konstante zuerst schreiben:
> nicht if (A==3)
> sondern if (3==A)

Ich hoffe, dass diese Unsitte irgendwann einmal ausgerottet wird.

Der Fehler des TE hat mit all deinen Mutmaßungen nicht das Geringste zu
tun und wurde übrigens schon 20 Minuten nach seine Anfrage gefunden. Du
versuchst gerade, den TE mit haltlosen Argumenten zu verwirren, nur weil
er die Dreistigkeit besitzt, eine andere als die von dir favorisierte
Programmiersprache zu verwenden.

: Bearbeitet durch Moderator
von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
1 lesenswert
nicht lesenswert
Yalu X. schrieb:
>> Es gibt ne Menge Leute, ie bei Vergleichen in C grundsätzlich die
>> Konstante zuerst schreiben:
>> nicht if (A==3)
>> sondern if (3==A)
>
> Ich hoffe, dass diese Unsitte irgendwann einmal ausgerottet wird.

Neuere GCC Versionen warnen ja schon ganz gut wenn man sich dann mal 
vertippt.

Yalu X. schrieb:
> Du
> versuchst gerade, den TE mit haltlosen Argumenten zu verwirren, nur weil
> er die Dreistigkeit besitzt, eine andere als die von dir favorisierte
> Programmiersprache zu verwenden.

Das macht er doch immer, ich wundere mich wieso er nicht noch seine 
unnütze Lernbetty erwähnt hat.
Von der Type kommt immer nichts weiter als eine penetrante 
Überheblichkeit.
Wenn danach wenigstens ein fachlich Korrekter und hilfreicher Beitrag 
käme, dann könnt man darüber hinwegsehen. Aber nein es kommt der 
allergrößte Unsinn aller Zeiten danach und das jedesmal.
Wollt ihr den geisteskranken nicht langsam mal weglöschen?
Dem seine Posts sorgen jedesmal bei vielen Leuten für Unmut.
Es kommt einer seiner Posts und dann 10 dahinter die das erstmal 
widerlegen müssen, damit ein TE nicht verwirrt wird.

Dirk B. schrieb:
> Das soll übersichtlicher sein? du musst zweimal die Variable suchen.
> Mir tun deine Leser leid,

Was er da vorschlägt is ja noch harmlos im Vergleich zu seinem Magic 
Numbers und goto Versuchten Code den er hier immer versucht anzubieten 
wie sauer Bier.

: Bearbeitet durch User

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]
  • [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.