Forum: PC-Programmierung C++ Integer aus Puffer holen


von Thorvin (Gast)


Lesenswert?

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

von Sven P. (Gast)


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

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

von Sven P. (Gast)


Lesenswert?

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.

von Thorvin (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.