2015-05-04 5 views
2

Я хотел бы вывести данные структуры в двоичный файл, но без каких-либо битов заполнения между информацией каждой переменной. Например:Как вывести двоичный файл в C без битов заполнения

struct s { 
    int i1; 
    short s1; 
    char c1; 
}; 
struct s example[2]; 

Если я использую fwrite(&example, sizeof(struct s), 2, file), двоичный файл по-прежнему имеет биты заполнения между ними, например, s1 и c1, а также от c1 к i1 (of the 2nd struct).

Что было бы хорошим подходом для удаления этих битов заполнения из выходного файла?

Спасибо! Любая помощь оценивается

+0

См. Принятый ответ на http://stackoverflow.com/questions/4306186/structure-padding-and-structure-packing – rslemos

+1

Это специфичный для компилятора файл. Какой компилятор вы используете? –

+0

Вы можете выполнить итерацию по массиву и написать каждый элемент структуры отдельно. – ace

ответ

4

Я просто предлагаю вручную чтение/запись членов структуры в отдельности. Упаковка, использующая ваши директивы компилятора, может привести к проблемам с неэффективностью и переносимостью с несвязанным доступом к данным. И если вам приходится иметь дело с контентом, легко поддерживать это позже, когда ваши операции чтения разбиваются на члены поля, а не на целые структуры.

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

Если вы хотите, чтобы обобщить картину и уменьшить количество шаблонных вы пишете, вы можете сделать что-то подобное в качестве основного примера, чтобы начать и построить на:

struct Fields 
{ 
    int num; 
    void* ptrs[max_fields]; 
    int sizes[max_fields]; 
}; 

void field_push(struct Fields* fields, void* ptr, int size) 
{ 
    assert(fields->num < max_fields); 
    fields->ptrs[fields->num] = ptr; 
    fields->sizes[fields->num] = size; 
    ++fields->num; 
} 

struct Fields s_fields(struct s* inst) 
{ 
    struct Fields new_fields; 
    new_fields.num = 0; 

    field_push(&new_fields, &inst->i1, sizeof inst->i1); 
    field_push(&new_fields, &inst->s1, sizeof inst->s1); 
    field_push(&new_fields, &inst->c1, sizeof inst->c1); 

    return new_fields; 
} 

Теперь вы можете использовать эту Fields структуры с функциями общего назначения для чтения и записи членов любой структуры, например, так:

void write_fields(FILE* file, struct Fields* fields) 
{ 
    int j=0; 
    for (; j < fields->num; ++j) 
     fwrite(fields->ptrs[j], fields->sizes[j], 1, file); 
} 

Это, как правило, немного легче работать, чем некоторый функционал for_each_field такой подход прием обратного вызова.

Теперь все, что вам не придется беспокоиться о том, когда вы создаете какую-то новую-структуру S, чтобы определить отдельную функцию для вывода struct Fields из экземпляра, чтобы затем включить все те общие функции, которые Вы написали, что работа с struct Fields в настоящее время работают с этим новый S type автоматически.

1

Многие компиляторы принимают параметр командной строки, который означает «структуры упаковки». Кроме того, многие принимают прагму:

#pragma pack(1) 

где 1 означает выравнивание байт, 2 означает, что 16-битное выравнивание слов, 4 означает, что 32-битное выравнивание слов и т.д.

0

Чтобы сделать вашу платформу решения независимой, вы можете создать функцию, которая записывает каждое поле struct по одному, а затем вызывает функцию для записи как можно большего количества из struct s.

int writeStruct(struct s* obj, size_t count, FILE* file) 
{ 
    size_t i = 0; 
    for (; i < count; ++i) 
    { 
     // Make sure to add error checking code. 
     fwrite(&(obj[i].i1), sizeof(obj[i].i1), 1, file); 
     fwrite(&(obj[i].s1), sizeof(obj[i].s1), 1, file); 
     fwrite(&(obj[i].c1), sizeof(obj[i].c1), 1, file); 
    } 

    // Return the number of structs written to file successfully. 
    return i; 
} 

Использование:

struct s example[2]; 
writeStruct(s, 2, file); 
Смежные вопросы