Влияние заполнения структуры в сериализации C (сохранение в файл) - PullRequest
1 голос
/ 05 апреля 2011

У меня есть следующие структуры в C:

typedef struct sUser {
    char name[nameSize];
    char nickname[nicknameSize];
    char mail[mailSize];
    char address[addressSize];
    char password[passwordSize];
    int totalPoints;
    PlacesHistory history;
    DynamicArray requests;
}User;

typedef struct sPlacesHistory {
    HistoryElement array[HistorySize];
    int occupied;
    int last;
}PlacesHistory;

и функции:

void serializeUser( User * user, FILE * fp ) {
    fwrite( user, nameSize + nicknameSize + mailSize + addressSize + passwordSize + sizeof( int ) + sizeof( PlacesHistory ), 1, fp );
    serializeDynamicArray( user -> requests, fp );
}

User * loadUser( FILE * fp ) {
    User * user = malloc( sizeof( User ) );
    fread( user, nameSize + nicknameSize + mailSize + addressSize + passwordSize + sizeof( int ) + sizeof( PlacesHistory ), 1, fp );
    user -> requests = loadDynamicArray( fp );

    return user;
}

Когда я загружаю структуру User и я печатаю этого пользователя (загружается из файла)поле "last" of placeHistory имеет значение 255 или -1, в зависимости от порядка полей структуры PlacesHistory.Но у пользователя, которого я сохранил, было -1 на этом члене.

Так что, когда я получаю 255, это явно неправильно ... Я подозреваю, что это связано с заполнением структуры.

Как я могу это сделатьэто так, что порядок полей в структуре не имеет значения?
Или каким критериям я должен следовать, чтобы все работало правильно?
Нужно ли переписывать / обрабатывать по одному элементу за раз??(Я хотел бы избежать этого из соображений эффективности)
Нужно ли сначала сериализовать в массив вместо файла?(Надеюсь, что нет .. потому что это подразумевает заранее знать размер всех моих структур из-за неправильно размещенного массива, что означает дополнительную работу, создающую функцию для каждой непростой структуры, чтобы узнать ее размер)

Примечание: *Размер определяемых констант
Примечание 2: DynamicArray - указатель на другую структуру.

Ответы [ 3 ]

1 голос
/ 05 апреля 2011

Да, это, вероятно, связано с заполнением перед totalPoints или history.

Вы можете просто написать sizeof(User) - sizeof(DynamicArray) и прочитать туда же. Конечно, это будет совместимо только до тех пор, пока ваши определения структуры и компилятор не изменятся. Если вам не нужны сериализованные данные из одной версии вашей программы для совместимости с другой версией, то вышеприведенное должно работать.

0 голосов
/ 05 апреля 2011

заполнение может быть вашей проблемой, потому что

nameSize + nicknameSize + mailSize + addressSize + passwordSize + sizeof( int ) + sizeof( PlacesHistory ) != sizeof( User ) 

так что последний член (и последний в структуре) остается унифицированным. Чтобы проверить это, сделайте memset (, 0, sizeof (User)) перед чтением из файла.

Чтобы исправить это, используйте #pragma pack (push, 1) до и #pragma pack (pop) после

0 голосов
/ 05 апреля 2011

Почему вы складываете все элементы по отдельности?Это просто добавляет много места для ошибок.Всякий раз, когда вы меняете свою структуру, ваш код может сломаться, если вы забыли изменить все места, где вы увеличиваете размер (фактически, почему вы добавляете его каждый раз?).

И, как вы подозреваливаш код также не учитывает заполнение структуры, поэтому вы можете пропустить до трех байтов в конце вашего блока данных (если ваш самый большой элемент составляет 4 байта).

Почему бы не sizeof(User) дополучить размер объема данных, которые вы читаете / пишете?Если вы не хотите сохранять его части (например, запросы), используйте структуру внутри структуры.(РЕДАКТИРОВАТЬ: Или, как предложил rlibby, просто вычтите размер части, которую вы не хотите читать.)

Я предполагаю, что размеры ваших строк не делятся на 4, поэтому у вас 3 байтаи, как таковой, возможно, что вы должны были прочитать «0xffffffff» (= -1), но в итоге просто прочитали «0xff000000» (= 255 при использовании байтов с прямым порядком байтов и предполагая, что ваша структура была обнулена изначально).

...