2016-04-16 12 views
0

Ich habe ein Array von Bytes, die aus dem Netzwerk kommen (und daher Big Endian) und ich möchte zwei dieser Bytes extrahieren, um zu __builtin_bswap16() zu übergeben und in Little-Endian zu konvertieren.Parsen von zwei Bytes vom Array zu einem uint16_t?

Wie erhalte ich die zwei Bytes, wenn ich den Offset kenne, die sie innerhalb des Arrays befinden?

+2

'atoi' und' atoll' wandelt eine String-Darstellung der Zahl in ein 'int' bzw.' long long' um. Ist Ihre 2-Byte-Ganzzahl als String-Repräsentation oder als 'uint16_t' in einem Byte-Array dargestellt? – GWW

+3

Bitte klären Sie Ihre Frage mit einem Minimum an Code. – Cyb3rFly3r

+0

Sorry, siehe Bearbeiten. – mezamorphic

Antwort

2

Um ein uint16_t aus einem Array von uint8_t ohne Angst vor Ausrichtung oder Aliasing-Probleme zu extrahieren und ohne erneute Umsetzung das, was Sie schon vom System zur Verfügung gestellt ist, verwenden Sie memcpy.

uint16_t val; 
memcpy(&val, ptr, sizeof val); 

Wenn es in Netzwerk (Big Endian) bestellen und die Sie konvertieren möchten es um (möglicherweise Little-Endian, aber nicht darauf beschränkt) zu hosten, verwenden ntohs wie von Sam Varshavchik beantwortet.

val = ntohs(val); 

Sie können es tun, indem Bytes verschieben, aber wenn Standard-Library-Funktionen bereits tun, was Sie wollen, dann würde ich sagen, Stick mit den Standard-Bibliotheksfunktionen * zumindest bis Sie einen zwingenden Grund haben nicht zu.

* POSIX-Standard in diesem Fall nicht C++ Standard.

+0

endlich. jemand erwähnt Mempy - die einzige wirklich tragbare Art und Weise. –

+0

Für zwei Bytes?!? – Joshua

0

Sie suchen wahrscheinlich nach ntohs(3).

+0

Das ist das gleiche wie __builtin_bswap(). Ich versuche jedoch, die zwei Bytes zu extrahieren, um daran zu gehen. – mezamorphic

+0

Sie meinen "unsigned char \ * ptr =/* etwas * /; uint16_t v = ((uint16_t) v [0] << 8) | v [1]"? –

+0

Ich denke schon, gibt es keine Funktion, die das umschließt? Ich war mir nicht sicher, ob reinterpet_cast funktionieren würde. – mezamorphic

0

Fall A:

value = ((uint16_t)(array[X]) << 8) | (uint16_t)array[X + 1]; 

Fall B:

value = ntohs(*(unit16_t*)(char*)(array + X)); 

Wenn die Art der Anordnung ist bereits der char char * Guss ist nicht erforderlich. Die meiste Zeit wird der Compiler es trotzdem herausfinden; aber technisch ist es undefiniertes Verhalten ohne es.

+0

Danke für Ihre Antwort. Gibt es einen gcc intrinsic, der das umschließt? Ich wäre überrascht, wenn nicht. – mezamorphic

+0

Wahrscheinlich nicht, aber ich gcc intrinsics nicht verfolgen. – Joshua

0

Ich nehme an, Ihre Quelldaten sind ein uint8_t*, da es nicht anders angegeben ist. Deshalb:

uint8_t *src = /* your source */; 

Sie wollen ein uint16_t zu einem bestimmten Offset zu extrahieren; Das bedeutet:

uint8_t high = src[offset], low = src[offset + 1]; 
uint16_t v = high << 8 | low; 

/* offset and offset+1 must be in a valid range */ 

Oder kompakte:

uint16_t v = (src[offset] << 8) | src[offset+1]; 

Dann v zu Little-Endian entsprechend konvertieren, aber bemerken Ebene bswap nicht genug. Dies liegt daran, __builtin_bswapX (wobei X ist die Anzahl der Bytes) einfach tauscht Bytes, die ist nicht entspricht htonX/ntohX: diese auch überprüfen Sie Ihre Maschine Endianness und, falls erforderlich, weitermachen und tauschen; Sonst sind sie ein No-Op. In der Tat, wenn Sie auf einer BE-Architektur sind, muss die htonX ein No-Op sein (Daten ist bereits BE) und umgekehrt.

+0

Hallo, könnten Sie näher erläutern, warum bswap nicht genug ist? – mezamorphic

+0

Oh Entschuldigung, ich meinte bswap16() – mezamorphic

+0

Wenn Sie auf einem BE sind, macht bswap LE. – edmz

Verwandte Themen