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


von Tom (Gast)


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)


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. (Gast)


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)


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)


Lesenswert?

Irgendwelche Warnungen bei maximalem Warnlevel?

von Stephan (Gast)


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)


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)


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)


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)


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. (thomase)


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)


Lesenswert?

Ich hatte das (kommende) Vorzeichen schon berücksichtigt;)

von Thomas E. (thomase)


Lesenswert?

Damit liegst du natürlich richtig.

von W.S. (Gast)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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