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

Я пишу плагин 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));

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

Какая-либо СУШИЛКА, но все еще удобные в сопровождении идеи?

5
задан badp 29 June 2010 в 14:22
поделиться

2 ответа

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

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 .

5
ответ дан 14 December 2019 в 08:47
поделиться

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

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

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 для каждой из ваших структур данных, но как только он у вас есть, вы можете читать, писать, проверять и распечатывать свои данные с помощью набора достаточно простые функции.

2
ответ дан 14 December 2019 в 08:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: