Forum: Compiler & IDEs Long in char Array umwandeln


von Jonas J. (Gast)


Lesenswert?

Hallo,
ich will eine long Variable in ein char Array umwandeln, sodass ich die 
4 Bytes der long Variable einzeln verwenden kann und bin 
überfragt(Anfänger).Ich hoffe ihr könnt mir helfen. Danke

von xfr (Gast)


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.

von Uwe (Gast)


Lesenswert?

union convert
 {
   char mychar[4];
   long mylong
 } c;

von Karl H. (kbuchegg)


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.

von Jonas J. (Gast)


Lesenswert?

Ah ja, genau danach hatte ich gesucht. Vielen Dank für die schnellen 
Antworten.

von Christopher C. (Gast)


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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dieses Type-Punning ist inspecified Behavior in C.

von B. S. (bestucki)


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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Es ist unspecified, nicht implementation defined.

"Ausprobieren" ist übrigens n tolls Design Pattern...

von Rolf Magnus (Gast)


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.

von Rolf Magnus (Gast)


Lesenswert?

Rolf Magnus schrieb:
> char b[sizeof a];

Hmrpf, muß natürlich unsigned char statt char heißen.

von xfr (Gast)


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.

von xfr (Gast)


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.

von Rolf Magnus (Gast)


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.

von Frank M. (ukw) (Moderator) Benutzerseite


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 ;-)

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.