Hallo zusammen! Ich schreibe eine Anwendung, die via UDP/IP ein Datenprotokoll entgegennimmt und in einen Puffer speichert. In diesem Protokoll stehen z.B. die ersten 4 Byte für eine Variable vom Typ "int". Diese möchte ich auch als "int" innerhalb meiner Anwendung weiterverwenden. Problem ist nun, dass diese 4 Byte in anderer Reihenfolge stehen (MSB First Byte Order), als dieses im Arbeitsspeicher der Fall ist. Beispiel: Der Wert 123456789 (=0x075BCD15) steht wie folgt im Protokoll: 07 5B CD 15 ...und nicht: 15 CD 5B 07 Erzeuge ich mir also einen int-Zeiger auf diese 4 Byte, dann stimmt der Wert nicht. Im Moment mach ich es so: Ich erstelle ein char-Array mit der Länge 4, schreibe die Werte dort "rückwärts" rein und erzeuge mir einen int-Zeiger darauf. Das funktioniert auch wunderbar. Frage ist: Kennt jemand eine elegantere Lösung, ohne ein zusätzliches char-Array erzeugen zu müssen? Und ohne den ursprünglichen Puffer zu beeinflussen? Vielen Dank
Du hast da verschiedene Probleme auf einmal: - Als Integer bitte einen uint32_t oder ähnlich, damit du eine feste Größe hast, logisch. - Der Unterschied zwischen Network- und Host-Byte-Order. Dazu enthält die GNU-LIBC einige Funktionen, um vom einen ins andere zu kommen. - Bitordnung, d.h., wo MSBit und LSBit stehen, daran kannst du selten etwas ändern, aber denk wenigstens ganz kurz drüber nach :-)
Erstens garantiert dir niemand, daß int 4 Byte groß ist. Deshalb macht es eher Sinn, hier int32_t oder uint32_t zu nehmen (aus stdint.h). Zweitens:
1 | #include <iostream> |
2 | #include <iomanip> |
3 | #include <stdint.h> |
4 | |
5 | |
6 | int main( int nargs, char **args ) |
7 | {
|
8 | unsigned char puffer[4] = { 0x07, 0x5B, 0xCD, 0x15 }; |
9 | |
10 | uint32_t wert = ( ( (uint32_t)puffer[0] << 24 ) |
11 | |
|
12 | ( (uint32_t)puffer[1] << 16 ) |
13 | |
|
14 | ( (uint32_t)puffer[2] << 8 ) |
15 | |
|
16 | ( (uint32_t)puffer[3] << 0 ) |
17 | );
|
18 | |
19 | std::cout << "wert = 0x" << std::setw(8) << std::setfill('0') |
20 | << std::hex << wert |
21 | << std::endl; |
22 | }
|
In dieser Form ist das Ganze auch portabel zwischen Maschinen mit Little Endian-Architektur (Intel) und solchen mit Big Endian-Architektur (fast alle anderen).
Klaus Wachtler wrote: > In dieser Form ist das Ganze auch portabel zwischen Maschinen mit > Little Endian-Architektur (Intel) und solchen mit > Big Endian-Architektur (fast alle anderen). Dann aber bitte statt char auch noch uint8_t. Zum Verständnis: Schieberei und Rechnerei ist solange portabel, wie man sich innerhalb der Grenzen eines Datentypes bewegt. Bricht man daraus aus, indem man z.B. vier uint8_t auf einen uint32_t projiziert (struct und memcpy, wie auch immer), geht das gerne schief. Für Worte und Doppelworte bietet sich sowas an: http://www.gnu.org/software/libc/manual/html_node/Byte-Order.html#Byte-Order Für alles andere: Eine Datenstruktur niemals direkt in die Socke schreiben, sondern Feld für Feld in geeignete und definierte Typen bringen und dann einzeln schreiben. Nachher umgekehrt.
ok, das mit den Datentypen fester Größe ist klar, hatte ich am Anfang in aller Schnelle nicht drüber nachgedacht. habe beide Lösungsvorschläge erfolgreich getestet, werde wohl die Funktion htonl() verwenden. Vielen Dank dafür!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.