2014-11-30 14 views
8

Ich weiß, dass Strukturen in C nicht Speicher angelegt werden können, wie sie im Code sind. Zum Beispiel:Lesen und Schreiben von Strukturen in C

struct a { 
    short x; 
    int y; 
}; 

unter der Annahme, 2-Byte-Kurzschlüsse und 4-Byte-Ganzzahlen, nehmen tatsächlich 8 Bytes im Speicher kann als der Compiler die Mitglieder auf 4 Bytegrenzen auszurichten will ... so gibt es 2 Byte slack zwischen x und y.

Dies macht das Lesen und Schreiben von Strukturen über Sprache, Compiler und Hardware nicht portierbar. Die einzige Möglichkeit, sie zu lesen und zu schreiben, ist Mitglied für Mitglied. Ja, Endianness ist auch hier ein Problem und der Austausch muss auf der Mitgliederebene erfolgen, aber nehmen wir an, dies ist kein Problem.

Fortran verfügt über einen 'Sequenz'-Spezifizierer für abgeleitete Typen (Strukturen), der dem Compiler mitteilt, die Elemente im Speicher so anzuordnen, wie sie angegeben sind. Dies ermöglicht das Lesen und Schreiben von abgeleiteten Typen.

Meine Frage ist: Gibt es eine Möglichkeit, eine ähnliche Sache in C auf eine tragbare (und wartbare) Weise zu tun?

+1

Die meisten Compiler haben Anweisungen zu * pack * -Strukturen, so dass sie andere (oder keine) Abstände zwischen den Elementen haben können. Eine schnelle Suche sollte Ihnen helfen, das zu finden, was Sie für Ihren Compiler benötigen. Das Endanfälligkeitsproblem ist jedoch nicht so leicht zu überwinden, aber wenn Sie nur eine einzelne Hardware-Plattform als Ziel haben, sollten Sie in Ordnung sein. –

+0

@JoachimPileborg oder fügen Sie eine BOM wie ein int '0xffffeeff' hinzu und fügen ein Byte-Swapping bei der Eingabe hinzu, je nachdem, wo der' ee' Satz –

+0

Serialize und Deserialize to Text ist und jedes Problem mit Endiannes, Packing und Portabilität vermeidet. – edc65

Antwort

2

Es gibt keine 100% saubere Lösung, die ich kenne. Normalerweise erzeuge ich zwei Headerdateien namens pack_on.h und pack_off.h. Um eine Struktur ohne Polsterung zu definieren:

#include <pack_on.h> 

struct a { 
    short x; 
    int y; 
} PACKED_STRUCTURE; 

#include <pack_off.h> 

Die Header-Dateien die Pragmas enthalten oder was auch immer benötigt wird, um die Compiler zu befriedigen, also so etwas wie:

#ifdef _MSC_VER 
#pragma pack(1) 
#define PACKED_STRUCTURE /* nothing */ 
#endif 

#ifdef __GNUC__ 
#define PACKED_STRUCTURE __attribute__(packed) 
#endif 

Wie Sie schon gesagt, wenn binäres Layout eine Problem, ist in der Regel auch Endianess wichtig. Dies wird in der obigen Lösung nicht angesprochen.

Bitte beachten Sie, dass es auch keine gute Idee ist, im gesamten Code gepackte Strukturen zu verwenden. Das Padding, das vom Compiler hinzugefügt wird, wenn Sie diese gepackten Strukturen nicht erzwingen, ist für schnellen Speicherzugriff nützlich. In vielen Anwendungen ist es am besten, diese gepackten Strukturen nur in einer Schicht Ihrer Anwendung zu verwenden, die sich mit dem Lesen und Schreiben dieser gepackten Strukturen beschäftigt, und kopieren Sie sie in richtig ausgerichtete Strukturen, bevor Sie sie in den Kern Ihrer Anwendung für weitere Bearbeitung.

+0

Und während des Entpackens können Sie auch das Byte-Swapping durchführen, um mit der Endianess umzugehen –

5

Ja, Fortran 2003 eingeführt, um die bind(C) Spezifizierer, die den Compiler genau wie der Begleiter C-Compiler das gleiche zu tun erzählt hat

type, bind(C) :: a 
    components 
end type 

Zusätzlich das iso_c_binding Modul (ein subpart des gesamten Fortran 2003 C Interoperabilität) definiert Konstanten, die Sie verbinden die C und Fortran intrinsische Arten helfen:

use intrinsic :: iso_c_binding, only: c_short, c_int 

type, bind(C) :: a 
    integer(c_short) :: x 
    integer(c_int) :: y 
end type 

Diese Art Interoperabilität mit Ihrem sein wird gesagt, C-Struktur

Die C-Interoperabilität wird in Compilern sehr häufig unterstützt. Es ist sehr schwierig, einen Compiler zu finden, der diese Funktion nicht unterstützt und immer noch von seinem Hersteller unterstützt wird.

Bleiben Sie weg von sequence beim Mischen von C und Fortran. Sequenztypen können gemäß dem Standard nicht interoperabel gemacht werden.