Как загрузить в динамическое расположение структур информацию двоичного файла? - PullRequest
0 голосов
/ 22 июня 2019

У меня есть двоичные файлы, которые содержат последовательность:

0-9 char name[10];
10-11 unsigned int n;
12-12+2x4n float coords[n][2];

, и мне нужно загрузить это в динамический массив структур.

Я хочу сохранить всю информацию намой файл в структурах типов: поэтому я объявил структуру, подобную этой:

typedef struct{
char name[10]
unsigned int n;
float coords[][2];
}sprites_t;

Затем я создаю функцию для загрузки этого в память:

    size_t n = 0;
        sprites_t * s = malloc(sizeof(sprites_t)*INITIAL_PACKAGE);
        size_t reads;

       while((reads = fread(s + n,sizeof(sprites_t),INITIAL_PACKAGE,fi)) == INITIAL_PACKAGE ){
            sprites_t * aux = realloc(s,sizeof(sprites_t) * (n+INITIAL_PACKAGE));
            if (aux == NULL) {
                free(s);
                return EXIT_FAILURE;
            }
            s = aux;
            n += INITIAL_PACKAGE;
        }
n += reads;

Я не могу сделать этовещь столько, сколько я хочу в памяти.Поскольку внутри двоичного файла у меня есть «unsigned int n», то есть количество строк, имеющих матрицу координат, то мои структуры являются гибкими.Как я могу читать это N?И на этом основании завершите строительные конструкции информацией, которую предоставляют файлы.

Я действительно не знаю, если мой код, если все в порядке.Если у кого-то есть другая стратегия загрузки информации в массив структур dinamyc, добро пожаловать.

1 Ответ

1 голос
/ 22 июня 2019

Если ваше двоичное поле name имеет длину ровно 10 символов, тогда вы, действительно, можете представить его как char[10], но вы должны знать, что, если оно надежно не завершает каждое имя (так что на самом деле можно использовать только 9)символы), тогда не безопасно обрабатывать этот массив так, как если бы он содержал строку C.Если вы хотите иметь возможность трактовать имя как строку, то объявите свой массив на один символ длиннее и используйте дополнительный пробел, чтобы обеспечить правильное завершение копий в памяти.

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

  1. Вы не можете иметь массив объектов с гибкими элементами массива, по крайней мере, там, где FAM содержат какие-либо данные.Даже динамический массив здесь не имеет смысла, потому что элементы не имеют одинакового размера.Связанный список будет лучшим выбором, или, может быть, хеш, введенный в поле name, если вы планируете искать их по имени.

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

    • , что представление вашей реализации в памяти типа unsigned int соответствует представлению двоичного файла по размеру, порядку байтов и (не) использованию заполнениябиты.Это, вероятно, совпадает с битами заполнения, так как они используются редко.Это может быть сделано в отношении порядка байтов.Вероятно, это не относится к размеру.
    • , что ваша реализация размещает тип sprites_t без каких-либо дополнений между концом name и началом n.Возможно, вам повезет, но вам нужно будет.Особенно, если ваш unsigned int шире, чем два байта, высока вероятность того, что структура структуры действительно содержит отступы.
  3. Гибкие элементы массива являются гибкими в том смысле, что программа может предоставить соответствующее количество места для них, не в том смысле, что они автоматически сгибаются.Вы, похоже, не предоставлять какой-либо пространство для вашей, если вы не читаете какой-либо, либо, так что это спорный вопрос на его лице.

Таким образом, общие предложения

1036 *

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

typedef struct sprite {
    char name[11];        // includes space for a terminator
    uint16_t n;           // matches the data, except maybe in byte order
    struct sprite *next;  // to link these together into a list
    float coords[][2];    // flexible array of 2D coordinates
} sprite_t;

чтение name, n и coords членов каждого спрайта отдельно

Наиболее простым было бы выделить каждую структуру только после того, как вы знаете, сколько существует наборов координат, поэтому, возможно,

char name[NAME_SIZE + 1] = { 0 };
uint16_t n;
if (fread(name, NAME_SIZE, 1, file) != 1) { /* handle EOF or I/O error ... */ }
if (fread(&n, 2, 1, file) != 1) { /* handle EOF or I/O error ... */ }
// swap n's byte order if appropriate ...
sprite_t *sprite = malloc(sizeof(sprite_t) + n * sizeof(sprite->coords[0]));
if (!sprite) { /* handle allocation failure ... */ }
if (fread(sprite->coords, sizeof(sprite->coords[0]), n, file) != n) { /* handle EOF or I/O error ... */ }
strcpy(sprite->name, name);
sprite->n = n;
append_to_linked_list(my_sprite_list, sprite);

Даже если это все еще предполагаетчто представление реализации типа float соответствует представлению, используемому в файле.Если этого не произойдет, то вам тоже нужно это исправить.Это может потребовать больше или меньше усилий, и «больше», безусловно, будет иметь место, если размеры не совпадают, хотя это маловероятно.

...