Long in char Array umwandeln

Gast #2894569
Lesenswert?

1
long a = 1234567;
2
char b[4];
3

4
b[0] = a >> 24;
5
b[1] = a >> 16;
6
b[2] = a >> 8;
7
b[3] = a;

Das wäre die Big-Endian-Reihenfolge. Wenn es andersrum sein soll, 
entsprechend die Positionen bzw. Shifts tauschen.
#2894595
Lesenswert?

unsigned char
bitte.


Für Bytes niemals char verwenden!
Bei char überlässt du es dem Compiler, ob da ein Vorzeichen angenommen 
werden soll oder nicht. Das ist aber nicht das, was man bei Bytes haben 
will. Bei Bytes gibt es kein Vorzeichen. Daher: sag das auch deinem 
Compiler und überlasse es nicht dem Zufall bzw. dem Compilerhersteller 
ob das so ist oder nicht.

Das unsigned kostet dich nichts, kann dich aber vor schwer zu findenden 
Fehlern bewahren, wenn der Compiler Default eben nicht unsigned ist.
Gast #2894648
Lesenswert?

Empfehlen würde ich dir auch den Datentyp uint8_t zu verwenden, unsigned 
char müsste nach Standard zwar sowieso sizeof(unsigned char) == 1 
ergeben, aber so bist du immer auf der sicheren Seite.
#2895254
Lesenswert?

Johann L. schrieb:
> Dieses Type-Punning ist inspecified Behavior in C.

Ist es nicht. Nur weil das im Standard als undefiniert beschrieben wird, 
heisst das noch lange nicht, dass das Verhalten irgendwie zufällig oder 
nicht reproduzierbar ist. Sondern nur, dass dieser Fall jeder Compiler 
handhaben kann wie er will (eher sein Entwickler).

Der Normalfall ist, dass überschüssige Bits einfach abgeschnitten 
werden.
Bsp.:
1
unsigned long int valueA=0x1234ABCD;
2
unsigned char valueB;
3
valueB=valueA;  /* in valueB steht nun 0xCD */

Zur Sicherheit das Handbuch fragen oder einfach ausprobieren.
Gast #2896137
Lesenswert?

be stucki schrieb:
> Johann L. schrieb:
>> Dieses Type-Punning ist inspecified Behavior in C.
>
> Ist es nicht. Nur weil das im Standard als undefiniert beschrieben wird,
> heisst das noch lange nicht, dass das Verhalten irgendwie zufällig oder
> nicht reproduzierbar ist. Sondern nur, dass dieser Fall jeder Compiler
> handhaben kann wie er will (eher sein Entwickler).

Undefiniertes Verhalten heißt auch, daß er es gar nicht explizit 
handhaben muß, so daß eben das rauskommt, was sich aus irgendwelchen 
anderen Umständen ergibt, auch wenn das sich je nach 
Compiler-Parametern, Optimierung oder anderen Dingen unterschiedlich 
verhält. Der Compiler-Bauer muß sich schlicht überhaupt nicht drum 
kümmern und nicht mal drüber nachdenken, was denn in dem Fall passiert.

Johann L. schrieb:
> Es ist unspecified, nicht implementation defined.

Immerhin darf man aber jedes Objekt in ein Array aus unsigned char 
gleicher Größe per memcpy kopieren, also so:
1
long a = 1234567;
2
char b[sizeof a];
3

4
memcpy(b, a, sizeof a);

Das dürfte aus ISO-C-Sicht die sauberste Variante sein und beim gcc auch 
nicht langsamer oder umständlicher als irgendwelche union-Verrenkungen 
oder Pointer-Castereien.
Gast #2896162
Lesenswert?

Rolf Magnus schrieb:
> Immerhin darf man aber jedes Objekt in ein Array aus unsigned char
> gleicher Größe per memcpy kopieren, also so:
> long a = 1234567;
> char b[sizeof a];
>
> memcpy(b, a, sizeof a);
>
> Das dürfte aus ISO-C-Sicht die sauberste Variante sein und beim gcc auch
> nicht langsamer oder umständlicher als irgendwelche union-Verrenkungen
> oder Pointer-Castereien.

Wenn man tatsächlich eine Kopie braucht, kann man das natürlich machen. 
Wenn es nur darum geht, auf einzelne Bytes zuzugreifen, erreicht man mit 
den "Union-Verrenkungen oder Pointer-Castereien" aber das Gleiche ohne 
die Daten kopieren zu müssen.

Das Problem ist nur (sowohl bei memcpy, Unions und Pointercasting), dass 
der Code nicht portabel ist, da auf anderer Hardware die 
Byte-Reihenfolge anders sein kann. Beim Shiften ist die Semantik dagegen 
unabhängig von der Bytereihenfolge, und bei einem klugen Compiler nicht 
langsamer als die anderen Methoden.
Gast #2896215
Lesenswert?

Streng genommen müsste man die Bits auf der linken Seite auch noch 
ausmaskieren, weil ja nicht garantiert ist, dass ein char 8 Bit breit 
ist:
1
unsigned long a = 1234567;
2
unsigned char b[4];
3

4
b[0] = (a >> 24) & 0xFF;
5
b[1] = (a >> 16) & 0xFF;
6
b[2] = (a >> 8) & 0xFF;
7
b[3] = a & 0xFF;

Das sollte dann wirklich koscher sein. Wenn man es öfters braucht, kann 
man es ja in ein Macro verpacken.
Gast #2896340
Lesenswert?

xfr schrieb:
> Wenn man tatsächlich eine Kopie braucht, kann man das natürlich machen.
> Wenn es nur darum geht, auf einzelne Bytes zuzugreifen, erreicht man mit
> den "Union-Verrenkungen oder Pointer-Castereien" aber das Gleiche ohne
> die Daten kopieren zu müssen.

Bei der Union mußt du auch kopieren, es sei denn, du verpackst gleich 
den ursprünglichen long in die Union rein. Ggf. mußt du da sogar zweimal 
kopieren, nämlich einmal den long in die union, dann das Ergebnis wieder 
raus in das Ziel-Array.

> Das Problem ist nur (sowohl bei memcpy, Unions und Pointercasting), dass
> der Code nicht portabel ist, da auf anderer Hardware die
> Byte-Reihenfolge anders sein kann. Beim Shiften ist die Semantik dagegen
> unabhängig von der Bytereihenfolge, und bei einem klugen Compiler nicht
> langsamer als die anderen Methoden.

Allerdings ist auch das Rechtsschieben von negativen Werten, wie sie ein 
long ja haben kann, nicht portabel.
Moderator Persönliche Seite #2896366
Lesenswert?

Rolf Magnus schrieb:
> Allerdings ist auch das Rechtsschieben von negativen Werten, wie sie ein
> long ja haben kann, nicht portabel.

Also long erst in einen unsigned long casten, dann schieben ;-)

Ich werfe diesen Vorschlag noch ins Feuer:
1
long a = 1234567;
2
unsigned char * b = (unsigned char *) &a;

Dann kann man mit b[0] bis b[3] auf die 4 Bytes lesend zugreifen. 
Allerdings hat man hier weder eine Kopie noch ist diese Lösung 
Endian-fest, dafür aber ist sie wohl die schnellste Lösung ;-)

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