2015-03-09 8 views
7

Heute habe ich ein Problem mit Swift-Strukturen festgestellt. Siehe folgende Struktur zum Beispiel:Swift berechnet die falsche Größe der Struktur

struct TestStruct { 
    var test: UInt16 
    var test2: UInt32 
} 

Ich würde davon ausgehen, dass die Größe dieser Struktur insgesamt 6 Bytes ist, weil UInt16 2 Bytes ist und UInt32 ist 4 Byte groß.

Der folgende Code druckt 6 (was richtig ist):

println(sizeof(UInt32) + sizeof(UInt16)) 

Aber wenn ich die Größe der Struktur mit

println(sizeof(TestStruct)) 

überprüfen druckt 8 und 6 nicht

Wenn ich das gleiche mit folgender Struktur versuche:

struct TestStruct2 { 
    var test: UInt16 
    var test2: UInt16 
    var test3: UInt16 
} 

Dann

println(sizeof(TestStruct2)) 

druckt den richtigen Wert: 6. Aber die Größe von TestStruct sollte die gleiche wie die Größe von TestStruct2 sein.

Warum ist die erste Struktur 8 Bytes groß? Mache ich etwas falsch oder ist das ein Fehler?

(mit Xcode 6.1.1 (6A2008a) auf OS X Mavericks, normale Kommandozeilen-Anwendung für Mac getestet)

+0

Google "Struct Alignment" und Sie werden den Grund sehen. Es ist ein allgemeines Verhalten. Zum Beispiel: https://msdn.microsoft.com/en-us/library/71kf49f1.aspx –

+0

Vergleichen http://stackoverflow.com/questions/28898277/why-does-some-types-float80-have-a- Speicherausrichtung - größer als Wortgröße. –

+0

Danke, dass Sie mich in die richtige Richtung weisen! Ich war mir dessen nicht bewusst, sorry. Ich bin immer noch neu in den unteren Programmiersprachen wie C und Objective-C. Aber wie kann ich dann Daten von NSData in diese ausgerichtete Struktur bekommen? Wenn ich data.getBytes (& aStruct, length: sizeof (AStruct)) verwende, dann habe ich falsche Werte. – user4650218

Antwort

8

Dies liegt daran, Swift UInt32 Feld bei einer 4-Byte-Grenze ausgerichtet ist, indem ein Zwei-Byte-Einfügen " Lücke "zwischen UInt16 und UInt32. Wenn Sie die Felder wechseln, so dass die 32-Bit-Feld zuerst kommt, würde die Lücke beseitigt:

struct TestStruct1 { 
    var test: UInt16 
    var test2: UInt32 
} 
println(sizeof(TestStruct1)) // <<== Prints 8 

struct TestStruct2 { 
    var test2: UInt32 
    var test: UInt16 
} 
println(sizeof(TestStruct2)) // <<== Prints 6 

Sie auch eine andere UInt16 in diese Lücke ohne Änderung der Größe der Struktur platzieren können:

struct TestStruct3 { 
    var test0: UInt16 
    var test1: UInt16 
    var test2: UInt32 
} 
println(sizeof(TestStruct3)) // <<== Prints 8 

Aber wie kann ich dann Daten von NSData in diese ausgerichtete Struktur bekommen? Wenn ich data.getBytes(&aStruct, length: sizeof(AStruct)) verwende, dann habe ich falsche Werte.

Nicht unbedingt: Wenn Sie AStruct unter Verwendung der gleichen Methode gespeichert, dann würden die Lücken dort auch in NSData sein, so dass Ihre binäre Daten zu erhalten, wie Platzieren „eine Ausstechform“ auf vorgefüllte Array von Bytes würde mit der gleichen Ausrichtung.

+0

Danke! Aber was, wenn ich die Felder nicht wechseln kann. Nehmen wir zum Beispiel den DNS-Ressourceneintrag, der 16-Bit-Name/-Zeiger, 16-Bit-Typ und 16-Bit-Klasse gefolgt von einem 32-Bit-TTL-Feld, dann einem 16-Bit-Längenfeld und einigen weiteren Feldern aufweist.Wenn ich die "Daten" für diesen Datensatz in einem NSData-Objekt habe, wie kann ich etwas wie "data.getBytes (& aStruct, length: sizeof (AStruct))" machen? Momentan bekomme ich wegen dieser Ausrichtung falsche Werte für TTL und Länge. – user4650218

+3

Eine interessante Tatsache (ich denke) ist, dass die Swift 'sizeof()' Funktion * nicht * das * trailing * struct Padding enthält - also unterscheidet es sich von der C 'sizeof'. Dafür braucht man 'strideof()'. Dies wurde in https://devforums.apple.com/message/1086107#1086107 besprochen. –

+0

@ user4650218 Wenn das Datenformat für Sie auf der Byte-Ebene angegeben ist, sollten Sie nicht versuchen, es direkt in eine typisierte Datenstruktur zu platzieren. Nimm das Array von Bytes und interpretiere deine Struktur ein Feld nach dem anderen: lese die ersten 16 Bits, interpretiere sie als Namen; dann nimm die nächsten 16 Bit und interpretiere es als einen Typ; fortfahren, bis die gesamte Struktur interpretiert ist. Sie können Feldern, die Sie lesen, Felder in Ihrer 'struct' zuweisen, aber jeweils einzeln. – dasblinkenlight