2016-12-23 6 views
3

Ist reinterpret_cast sicher dafür, und ist das der beste Weg, dies zu tun?In eine vorzeichenbehaftete Ganzzahl schreiben, als ob sie in C++ vorzeichenlos ist

Zum Beispiel habe ich im folgenden Code eine Klasse ibytestream, die das Lesen von uint16_t s und int16_t s davon ermöglicht. ibytestream::next ist ein vector<unsigned char>::iterator.

inline ibytestream& operator>>(ibytestream& stream, uint16_t& data) { 
    data = 0; 
    data |= *stream.next++; 
    data <<= 8; 
    data |= *stream.next++; 
    return stream; 
} 

inline ibytestream& operator>>(ibytestream& stream, int16_t& data) { 
    return stream >> reinterpret_cast<uint16_t&>(data); 
} 

Ich will nicht, um den Code duplizieren, um das Bytes in einer ganzen Zahl konvertieren, so habe ich reinterpret_cast für die signierte Version des Code aus der unsignierten Version wieder zu verwenden. Es funktioniert gut auf meiner Maschine, aber wird es im Allgemeinen auf anderen modernen Maschinen funktionieren?

+0

Würde dies nicht gegen die strenge Aliasing-Regel verstoßen? http://StackOverflow.com/q/98650/417197 –

+1

@Andre die Regel ermöglicht für Aliasing zwischen einem Integer-Typ und seiner signierten/unsignierten Variante –

Antwort

3

Ja, das ist sicher.

Drei Teile des Standards gelten diese Bestimmung vorzunehmen:

  1. Ausrichtung Anforderungen mit und ohne Vorzeichen Typen sind die gleichen
  2. Zeiger zwischen Zeiger auf Typen mit identischer Ausrichtung Anforderungen wirft erlaubt
  3. Wenn Umsetzungen zwischen glvalues ​​werden durchgeführt, die Umwandlung ist gültig, wenn die Umwandlung zwischen den entsprechenden Zeigern gültig ist.

Für jede der Standard-Integer-Typen signiert, existiert eine entsprechende (jedoch unterschiedlichen) -Standard unsigned integer Typ: unsigned char, unsigned short int, unsigned int, unsigned long int, und unsigned long long int, von denen jeweils die gleiche Menge einnimmt Lagerung und hat die gleichen Ausrichtung Anforderungen.

Ein Objektzeiger kann explizit in einen Objektzeiger eines anderen Typs konvertiert werden. Die Umwandlung eines Prwerts vom Typ "Zeiger in T1" in den Typ "Zeiger auf T2" (wobei T1 und T2 Objekttypen sind und die Ausrichtungsanforderungen von T2 nicht strenger als die von T1 sind) und zurück zu seinem ursprünglichen Typ ergibt das Original Zeigerwert.

Ein glvalue-Ausdruck vom Typ T1 kann in den Typ "Verweis auf T2" umgewandelt werden, wenn ein Ausdruck vom Typ "Zeiger auf T1" explizit in den Typ "Zeiger auf T2" mit einem reinterpret_cast konvertiert werden kann. Das Ergebnis verweist auf dasselbe Objekt wie der Quell-gl-Wert, aber mit dem angegebenen Typ.

+0

Ich glaube, du verpasst den Teil, auf den sich M.M in seinem Kommentar bezieht; dass Sie auf ein vorzeichenbehaftetes Integer-Objekt über einen Ausdruck des entsprechenden vorzeichenlosen Typs zugreifen können. – MSalters

1

Ja, das sollte vollkommen in Ordnung sein. (Moving zwischen ints und Byte-Feldern haben potentielle Bytereihenfolge Probleme, aber das ist eine andere Sache, die sowohl mit und ohne Vorzeichen Zahlen gilt.)

etwas ganz anderes: Dieses Bit:

data = 0; 
data |= *stream.next++; 

... können vereinfacht werden:

data = *stream.next++; 
+0

Ich glaube nicht, dass mein Code Endianness Probleme haben wird. Die Bytes werden immer in Big-Endian gelesen, unabhängig von der Endianz der zugrunde liegenden Maschine. Außerdem habe ich die Vereinfachung nicht gemacht, so dass der Code konsistent aussehen würde (d. H. "Data | = * stream".next ++; 'wiederholt sich über mehrere Zeilen), und ich würde annehmen, dass mein Compiler schlau genug ist, um ihn zu optimieren. – Bernard

+0

Es ist nur ein Problem, wenn Sie Portabilität über Architekturen hinweg benötigen und es scheint, dass Sie es nicht brauchen. Alles gut. –

Verwandte Themen