Forum: Compiler & IDEs AVR-GCC: Unklarheit wie Datenbreite behandelt wird


von Micha (Gast)


Lesenswert?

ich bastel akut an der Ansteuerung einer SD-Karte, bin dabei im AVR-GCC 
über einen Effekt gestolpert der mein "Schulwissen" in Frage stellt. Und 
zwar berechne ich aus drei Variablen eine Blocknummer, letztere soll 32 
Bit breit sein. Zuerst hab ich das so gemacht:
1
uint8_t  hstdsk;  // Wertebereich 0..15
2
uint16_t hsttrk;  // Wertebereich 0..511
3
uint8_t  hstsec;  // Wertebereich 0..31
4
uint32_t blockno; // Blocknummer für SD-Karte, 0..262143
5
6
...
7
8
blkno = hstsec + (hsttrk << 5) + (hstdsk << 14);
Musste feststellen, dass blkno dann immer ein 16-Bit breites Ergebnis 
bekommt. Als nächstes hab ich ein explizites cast in die Zuweisung 
geschrieben, also so:
1
blkno = (uint32_t) (hstsec + (hsttrk << 5) + (hstdsk << 14));
Das hat ebenfalls nicht geholfen. Erst nachdem ich alle beteiligten 
Variablen als uint32_t definiert hatte kam das gewünschte Ergebnis 
heraus. Verhält sich das AVR-GCC hier anders als Standard-C oder hab ich 
einen Denkfehler?

von Micha (Gast)


Lesenswert?

P.S. dass die 32 Bit Variable oben blockno und in der Zuweisung blkno 
heisst war mein Fehler beim Abschreiben, hat mit dem beschriebenen 
Effekt nix zu tun, sorry.

von Peter II (Gast)


Lesenswert?

Micha schrieb:
> Verhält sich das AVR-GCC hier anders als Standard-C oder hab ich
> einen Denkfehler?

C rechnet immer mit int (also in deinen fall mit 16bit). (oder mehr wenn 
es größere Datentypen sind).

blkno = (uint32_t) (hstsec + (hsttrk << 5) + (hstdsk << 14));

dein cast auf uint32_t bringt hier überhaupt nichts. Weil recht nur mit 
16bit gerechnet wird.

blkno = (uint32_t)hstsec + ((uint32_t)hsttrk << 5) + ((uint32_t)hstdsk 
<< 14));


so müsste es richtig sein.

von Micha (Gast)


Lesenswert?

Peter II schrieb:
> C rechnet immer mit int (also in deinen fall mit 16bit). (oder mehr wenn
> es größere Datentypen sind).

Wie das praktische Experiment zeigt hast Du recht. Ich hatte bisher 
immer in dem Glauben gelebt dass eine C Zuweisung auf den "breitesten" 
beteiligten Datentyp castet. Wieder was dazugelernt.

von Peter II (Gast)


Lesenswert?

Micha schrieb:
> Wie das praktische Experiment zeigt hast Du recht. Ich hatte bisher
> immer in dem Glauben gelebt dass eine C Zuweisung auf den "breitesten"
> beteiligten Datentyp castet. Wieder was dazugelernt.

in der Rechnung ist der breitesten Datentype doch ein uint16_t. Damit 
stimmt deine aussage. Wo das Ergebnis landen, spielt ja für die Rechnung 
keine rolle.

von Fabian O. (xfr)


Lesenswert?

Bei den angegebenen Wertebereichen würde es reichen, nur den Parameter 
hstdsk in uint32_t zu casten:
1
blkno = hstsec + (hsttrk << 5) + ((uint32_t) hstdsk << 14);

Der Wert (hsttrk << 5) kann maximal 16352 werden (bei Eingangsbereich 
0..511). Auch mit hstsec (0..31) wird es nicht über 16383. Die letzte 
Addition wird mit 32 Bit durchgeführt, da der rechte Operand 32 Bit 
breit ist.

Zur Sicherheit würde ich aber auch den zweiten Shift in 32 Bit rechnen:
1
blkno = hstsec + ((uint32_t) hsttrk << 5) + ((uint32_t) hstdsk << 14);

von Micha (Gast)


Lesenswert?

Vielen Dank!

Das war für mich 'ne wirklich sehr hilfreiche Diskussion. Hatte bisher 
immer angenommen, wenn auf der linken Seite der Zuweisung eine 32 Bit 
breite Variable steht, dass dann auch alles rechts vom = alles in der 
Breite von 32 Bit stattfindet.

Dank dieses Beispiels verstehe ich es jetzt so dass eine Zuweisung nicht 
komplett gecastet wird, sondern nur die Seite rechts vom =

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.