AVR-GCC: Unklarheit wie Datenbreite behandelt wird

Gast #3397134
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?
Gast #3397147
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.
Gast #3397159
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.
Gast #3397162
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.
#3397246
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);
Gast #3397257
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 =

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren