2010-05-27 22 views
5

Die Code-Basis bei der Arbeit enthält einigen Code, der in etwa wie folgt aussieht:Wie interpretiere ich binäre Daten als Integer?

#define DATA_LENGTH 64 

u_int32 SmartKey::SerialNumber() 
{ 
    unsigned char data[DATA_LENGTH]; 
    // ... initialized data buffer 
    return *(u_int32*)data; 
} 

Dieser Code funktioniert einwandfrei, aber GCC gibt die folgende Warnung:

warning: dereferencing pointer ‘serialNumber’ does break strict-aliasing rules 

Kann jemand diese Warnung erklären? Ist dieser Code potentiell gefährlich? Wie kann es verbessert werden?

aktualisieren
Mit Dank an James McNellis' Antwort kam ich auf die folgende Nutzenfunktion auf:

template<class T, class Data> 
T BinaryCast(const Data & inData) 
{ 
    T ret; 
    std::copy(&inData[0], &inData[0] + sizeof(ret), reinterpret_cast<char*>(&ret)); 
    return ret; 
} 

u_int32 SmartKey::SerialNumber() 
{ 
    unsigned char data[DATA_LENGTH]; 
    // ... initialized data buffer 
    return BinaryCast<u_int32>(data); 
} 

Fühlen Sie sich frei Verbesserungen vorschlagen!

+0

Wahrscheinlich hat mit Zeiger aus unsigned Char * zu u_int32 *, aber eine lange Zeit seit ich C++ getan hatte zu tun. Wenn ja, da DATA_LENGTH ein genaues Vielfaches von 32 ist, sollte kein Problem auftreten. –

Antwort

11

Die Warnung ist, weil Sie die strict aliasing rule verletzen.

Eine Möglichkeit, es richtig zu tun wäre, um die Bytes aus dem data Puffer in ein u_int32 Objekt zu kopieren und das Objekt zurückgeben:

unsigned char data[DATA_LENGTH]; 
// ... initialized data buffer 

u_int32 i; 
assert(sizeof (i) <= DATA_LENGTH); 
std::copy(&data[0], &data[0] + sizeof (i), reinterpret_cast<char*>(&i)); 
return i; 

Diese Lösung funktioniert, weil in C++ es jede Art von zugreifen darf Objekt als ein Array von char.

(std::copy() ist in <algorithm>)

+0

Genau das, was ich posten wollte. Obwohl meine Lösung memcpy verwendet. – PeterK

+1

Auch wenn Sie nicht mit STL arbeiten, verwenden Sie zumindest reinterpret_cast. – user347594

+0

Eine Feinheit, die erwähnt werden sollte, wenn über Daten auf diese Weise (de) serialisiert wird, ist die Endianness. Es ist jetzt weniger wichtig, dass Apple Intel-Chips verwendet, aber Sie sollten nicht vergessen, dass Ihre Daten stark beschädigt werden. – user168715

2

In C und C++ Sprachen Speicher durch das Objekt eines Typs als Objekt eines anderen Typs besetzt neu zu interpretieren ist illegal - es führt zu undefiniertem Verhalten. Einige Compiler verwenden diese Regel, um aggressive Aliasing-bezogene Optimierungen durchzuführen. Daher funktioniert Ihr Code möglicherweise nicht wie erwartet, wenn Sie die oben genannte Neuinterpretation durchführen.

In C/C++ ist es OK, jedes Objekt als ein Array von Zeichen neu zu interpretieren, aber es ist nicht OK, ein eigenständiges Array von Zeichen zu nehmen und Reinterpret als Objekt eines anderen Typs zu interpretieren. Das macht dein Code.

Zusätzlich zu Alias-Problemen müssen Sie berücksichtigen, dass ein eigenständiges automatisches Char-Array nicht garantiert korrekt ausgerichtet ist, um als u_int32-Wert gelesen zu werden.

Der richtige Weg, was der oben genannte Code zu tun ist, zu tun versucht, den Quell-Array in einen Zwischen u_int32 Wert kopieren mit memcpy

u_int32 SmartKey::SerialNumber() 
{ 
    unsigned char data[DATA_LENGTH]; 
    u_int32 u; 
    // ... 
    memcpy(&u, data, sizeof u); 
    return u; 
} 

Natürlich müssen Sie sicher sein, dass die endianness des Daten sind identisch mit der Endianz der u_int32 Objekte auf Ihrer Plattform.

-1

nicht sicher, aber ich glaube, Sie so tun können:

return (u_int32)&data; 
+0

Das wird die Adresse von 'Daten' in' u_int32' umwandeln. Das OP möchte den tatsächlichen Inhalt lesen, der in den ersten Datenelementen gespeichert ist. Nicht einmal im Entferntesten das Gleiche. – AnT

0

Ich denke, das Problem tatsächlich irgendwo in Ihrem elided Code ist es, die Daten [] Struktur zu initialisieren. Ich denke nicht, dass es etwas mit deiner Besetzung zu tun hat, was in Ordnung ist.

Verwandte Themen