Forum: Mikrocontroller und Digitale Elektronik Nur ein Byte aus einem 32Bit-Wort herausziehen - wie am besten?


von Hans (Gast)


Lesenswert?

Hi zusammen!

Ich habe ein Datenwort mit 32Bit Länge - das möchte ich nun in Bytes 
umbasteln.

Hier gibt es ja mehrere Möglichkeiten, mit Pointer und ohne - der 
Einfachheit halber lieber ohne Pointer. Aber hier gehen ja auch noch 
verschiedene Sachen...

Also:
1
uint32_t data = 83749; // nur als Beispiel
2
uint8_t bytes[4];
3
4
// Variante 1:
5
6
bytes[0] = (uint8_t) (data >> 24);
7
bytes[1] = (uint8_t) (data >> 16);
8
bytes[2] = (uint8_t) (data >> 8);
9
bytes[3] = (uint8_t) data;
10
11
// Variante 2:
12
13
bytes[0] = (data >> 24) & 0xFF;
14
bytes[1] = (data >> 16) & 0xFF;
15
bytes[2] = (data >> 8) & 0xFF;
16
bytes[3] = data & 0xFF;
17
18
// geht auch sowas:
19
20
bytes[0] = (data & 0xFF000000);
21
bytes[1] = (data & 0xFF0000);
22
bytes[2] = (data & 0xFF00);
23
bytes[3] = data & 0xFF;

Oder gibt es eine noch bessere Möglichkeit?

von Tip (Gast)


Lesenswert?

Du könntest eine union anlegen und kommst dann evtl. einfacher ans Bit 
ran. Das kommt auf den Kontext an, d.h. wonach bestimmt sich das Bit und 
wohin soll es, wenn du es rausgezogen hast.

mfg

von Nico S. (Gast)


Lesenswert?

eine Union!
1
union
2
{
3
    uint32_t zahl;
4
    uint8_t byte[4];
5
} uni;
6
7
int main(void) {
8
    uni myvar;
9
    myvar.zahl = 30923;
10
11
    if(myvar.byte[1] == 5) { }
12
    return 0;
13
}

von Werner B. (werner-b)


Lesenswert?

Das funktioniert jedenfalls nicht !
1
/* FALSCH ! */
2
bytes[0] = (data & 0xFF000000);
3
bytes[1] = (data & 0xFF0000);
4
bytes[2] = (data & 0xFF00);
Müsste so aussehen:
1
bytes[0] = (data & 0xFF000000) >> 24;
2
bytes[1] = (data & 0xFF0000) >> 16;
3
bytes[2] = (data & 0xFF00) >> 8;

Und dann gibt es da noch die "Edianness" zu berücksichtigen.
http://en.wikipedia.org/wiki/Endianness
bzw.
http://de.wikipedia.org/wiki/Endianness

von Michael H. (morph1)


Lesenswert?

Die muss er nur berücksichtigen wenn er ein Union verwendet, beim 
Shiften und Maskieren kann ihm die egal sein.

von Hans (Gast)


Lesenswert?

OK, vielen Dank schonmal!

Ist denn zwischen den beiden
1
// Variante 1:
2
3
bytes[0] = (uint8_t) (data >> 24);
4
bytes[1] = (uint8_t) (data >> 16);
5
bytes[2] = (uint8_t) (data >> 8);
6
bytes[3] = (uint8_t) data;
7
8
// Variante 2:
9
10
bytes[0] = (data >> 24) & 0xFF;
11
bytes[1] = (data >> 16) & 0xFF;
12
bytes[2] = (data >> 8) & 0xFF;
13
bytes[3] = data & 0xFF;
ein Unterschied, weshalb das eine dem anderen vorziehen sollte?

von Hans (Gast)


Lesenswert?

Man kann das 0xFF ja theoretisch auch weglassen und das umcasten ebenso.

von (prx) A. K. (prx)


Lesenswert?

Was spricht gegen:
1
bytes[0] = data >> 24;
2
bytes[1] = data >> 16;
3
bytes[2] = data >> 8;
4
bytes[3] = data;
wenn man mal davon ausgeht, dass ein Byte 8 Bits hat?

Ein nicht zu dämlicher Compiler wird daraus Code erzeugen, der nicht 
schlechter ist als der Weg über eine Union, oft hingegen besser.

von Klaus (Gast)


Lesenswert?

Hans schrieb:
> OK, vielen Dank schonmal!
>
> Ist denn zwischen den beiden// Variante 1:
>
> bytes[0] = (uint8_t) (data >> 24);
> bytes[1] = (uint8_t) (data >> 16);
> bytes[2] = (uint8_t) (data >> 8);
> bytes[3] = (uint8_t) data;
>
> // Variante 2:
>
> bytes[0] = (data >> 24) & 0xFF;
> bytes[1] = (data >> 16) & 0xFF;
> bytes[2] = (data >> 8) & 0xFF;
> bytes[3] = data & 0xFF;
> ein Unterschied, weshalb das eine dem anderen vorziehen sollte?

Ich hatte mit einem DSP zu tun der mit 16-Bit je Adresse gearbeitet hat. 
Dadurch ist 16-Bit die kleinste addressierbare Einheit. Ein unsigned 
char war zwar sizeof(unsigned char)=1 aber mit 16-Bit Wertebereich. 
Variante 1 hätte auf dieser Plattform nicht das gewünschte Ergebnis 
geliefert (ich habe stundenlang nach dem Fehler gesucht: Der Cast nach 
unsigned char hat hier 16-Bit stehen lassen).

Ich persönlich nutze seither immer Variante 2, auch wenn ich der Meinung 
bin das das beobachtete Verhalten mehr ein Compilerproblem war...

von Werner B. (werner-b)


Lesenswert?

Es gab/gibt eine AVR-GCC Version (fragt bitte nicht welche) die
1
bytes = (ulong & 0xFF000000UL) >> 24;
in ein elegantes "move byte from register to register" übersetzt hat, 
und
1
bytes = ulong >> 24;
in eine Schleife mit 24 shift Operationen quer durch vier Bytes.

Darum habe ich mir das gemerkt und prüfe (fast) immer was der Compiler 
aus der jeweiligen Version macht.

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.