2014-11-30 16 views
8

Wiem, że w C struktura nie może być pustą pamięcią, tak jak w kodzie. Na przykład:Struktury odczytu i zapisu w C

struct a { 
    short x; 
    int y; 
}; 

zakładając szorty 2 bajtów i 4 ints bajt może rzeczywiście wziąć 8 bajtów w pamięci jako kompilator chce wyrównać członków 4 bajtowych granicach ... więc nie ma 2 bajty luzu między X i Y.

To sprawia, że ​​czytanie i pisanie nie jest możliwe w języku, kompilatorze i sprzęcie. Jedynym sposobem na ich odczytanie i zapisanie jest członek według członków. Tak, problemem jest również Endianness, a zamiana musi zostać wykonana na poziomie członków, ale załóżmy, że to nie jest problem.

Fortran ma "sekwencyjny" specyfikator dla typów pochodnych (struktur), który mówi kompilatorowi, aby rozmieścić elementy w pamięci, gdy są one podane. Umożliwia to przenośne odczytywanie i zapisywanie typów pochodnych.

Moje pytanie brzmi: czy istnieje sposób na wykonanie podobnej czynności w C w sposób przenośny (i konserwowalny)?

+1

Większość kompilatorów ma dyrektywy * do pakowania * struktur, więc może mieć inne (lub żadne) dopełnienie między elementami. Szybkie wyszukiwanie powinno pomóc ci znaleźć to, czego potrzebujesz dla swojego kompilatora. Jednak problem z endianizmem nie jest tak łatwy do pokonania, ale jeśli kierujesz tylko jedną platformę sprzętową, powinieneś być w porządku. –

+0

@JoachimPileborg lub dodasz BOM jak int '0xffffeeff' i dodajesz zamieniające bajt na dane wejściowe w zależności od tego, gdzie zestaw' ee' jest –

+0

Serializuj i deserializuj na tekst i unikaj problemów z estetyką, pakowaniem i przenośnością. – edc65

Odpowiedz

2

Nie ma w 100% czystego rozwiązania, które znam. Zazwyczaj tworzę dwa pliki nagłówkowe o nazwach pack_on.h i pack_off.h. Aby zdefiniować strukturę bez wyściółki:

#include <pack_on.h> 

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

#include <pack_off.h> 

Pliki nagłówkowe zawierają pragma lub co jest potrzebne, aby spełniać swoje kompilatora, czyli coś w rodzaju:

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

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

Jak już powiedziałem, gdy układ binarny jest problem, endianness jest zazwyczaj również ważne. Nie dotyczy to powyższego rozwiązania.

Należy również pamiętać, że używanie uszkodzonych struktur w całym kodzie jest również złym pomysłem. Wypełnienie dodane przez kompilator, gdy nie wymuszane są te spakowane struktury, jest przydatne do szybkiego dostępu do pamięci.

W wielu aplikacjach najlepiej używać tych spakowanych struktur tylko w jednej warstwie aplikacji, która zajmuje się odczytywaniem i pisaniem spakowanych struktur, i skopiować je do odpowiednio dopasowanych struktur przed wprowadzeniem ich do rdzenia aplikacji dalsze przetwarzanie.

+0

Podczas rozpakowywania możesz również zamienić bajt, aby poradzić sobie z endiansem –

5

Tak, Fortran 2003 wprowadził bind(C) specyfikator który informuje kompilator, aby zrobić dokładnie takie same, jak towarzysz kompilator C robi

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

Dodatkowo moduł iso_c_binding (A podsekcja całego Fortran 2003 C interoperacyjności) definiuje stałe, które pomagają połączyć C i Fortran wewnętrzne typy:

use intrinsic :: iso_c_binding, only: c_short, c_int 

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

Tego typu nazywa się interoperacyjne ze swoimi C struct.

Współdziałanie C jest bardzo szeroko obsługiwane w kompilatorach. Bardzo trudno jest znaleźć kompilator, który nie obsługuje tej funkcji i jest nadal obsługiwany przez jego dostawcę.

Podczas mieszania C i Fortran należy trzymać się z dala od sequence. Typy sekwencji nie mogą być współdziałające zgodnie ze standardem.

Powiązane problemy