Массивы хранятся как указатель или полностью внутри структур C? (было: Как вывести структуры на диск, когда некоторые поля являются указателями?) - PullRequest
5 голосов
/ 25 марта 2010

Я пишу плагин FUSE на C. Я отслеживаю структуры данных в файловой системе с помощью таких структур, как:

typedef struct {
    block_number_t inode;
    filename_t filename; //char[SOME_SIZE]
    some_other_field_t other_field;
} fs_directory_table_item_t;

Очевидно, что я должен прочитать (записать) эти структуры с (на) диск в какой-то момент. Я мог бы рассматривать структуру как последовательность байтов и сделать что-то вроде этого:

read(disk_fd, directory_table_item, sizeof(fs_directory_table_item_t));

... за исключением того, что это не может работать, поскольку filename на самом деле является указателем на массив char.

Я бы действительно хотел избежать написания кода вроде:

read(disk_df, *directory_table_item.inode,       sizeof(block_number_t));
read(disk_df,  directory_table_item.filename,    sizeof(filename_t));
read(disk_df, *directory_table_item.other_field, sizeof(some_other_field_t));

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

Какие-нибудь СУХИЕ, но все еще поддерживаемые идеи?

Ответы [ 2 ]

5 голосов
/ 25 марта 2010

Память строки будет частью вашей структуры, хотя во многих случаях тип массива повышается до до указателя, тип, хранящийся в структуре, - это массив, а не указатель.

typedef struct {
    block_number_t inode;
    filename_t filename; //char[SOME_SIZE]
    some_other_field_t other_field;
} fs_directory_table_item_t;

Итак, ваше заявление о прочтении:

read(disk_fd, directory_table_item, sizeof(fs_directory_table_item_t));

будет работать и вводить данные.

При чтении и записи блоков памяти следует учитывать заполнение . Заполнение - это дополнительные пустые поля, добавленные компилятором для выравнивания данных по соответствующим границам; например 32-байтовое значение часто должно начинаться с 4-байтовой границы в памяти, чтобы процессор мог его эффективно считывать. Обычно это не является проблемой, но при сохранении структуры на диск это может вызвать проблемы, если вы перекомпилируете код с другим параметром. Часто есть какие-то директивы #pragma, которые отключают заполнение, я думаю, что в MS Visual c ++ оно называется #pragma pack.

2 голосов
/ 25 марта 2010

Один из способов сделать это - создать статические таблицы данных const, которые описывают ваши структуры, чтобы с ними мог работать простой механизм чтения / записи.

Вам необходимо определить структуру, которая может представлять все, что вам нужно знать, чтобы прочитать или написать одно поле одной структуры.

typedef struct {
    char * name;
    size_t offset;
    size_t size;
    int    format_as;
    void*  format_struct; // if format_as & IS_STRUCT, this is the structure type
    } field_info_t

enum {
    AS_CHAR =1,
    AS_SHORT,
    AS_LONG,
    // add other types here
    AS_MASK = 0xFF,

    // these flags can be OR'd with type to refine the behavior
    IS_POINTER = 0x100,
    IS_STRUCT  = 0x200,
    };

Затем создайте из них таблицы, которые описывают все ваши структуры данных.

#define FIELD_OFF(type, field)    ((size_t)(LONG_PTR)&(((type *)0)->field))
#define FIELD_SIZE(type, field)   (sizeof(((type *)0)->field))

static const field_info_t g_fs_directory_table_item_table[] = {
    { "inode",
      FIELD_OFF(fs_directory_table_item_t, inode),
      FIELD_SIZE(fs_directory_table_item_t, inode),
      AS_LONG,
      NULL
    },

    { "filename",
      FIELD_OFF(fs_directory_table_item_t, filename),
      sizeof(filename_t),
      AS_CHAR | IS_POINTER,
      NULL
    },

    { "other_field", 
      FIELD_OFF(fs_directory_table_item_t, other_field),
      FIELD_SIZE(fs_directory_table_item_t, other_field),
      AS_STRUCT,
      &some_other_field_table,
    },
};

А затем читайте и пишите движки, которые получают указатель на структуру и указатель на таблицу, описывающую структуру, и читают / пишут различные поля.

void ReadStructure(FILE * fh, void * pStruct, field_info_t * pFields, int num_fields)
{
    // this is just a rough sketch of the code.
    for (int ii = 0; ii < num_fields; ++ii)
    {
       int  * field_size = pFields[ii].size;
       char * pfield = (char*)pStruct + pFields[ii].offset;
       if (pFields[ii].format_as & AS_POINTER)
           pfield = *(char**)pfield;  

       switch (pFields[ii].format_as & AS_MASK)
       { 
           case AS_CHAR:
           ....
       }         
    }
}
void WriteStructure(FILE * fh, void * pStruct, field_info_t * pFields, int num_fields);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...