Как создать структуру с двумя массивами переменного размера в C - PullRequest
1 голос
/ 03 августа 2009

Я пишу легковесную функцию сериализации и мне нужно включить в нее два массива переменного размера.

  • Как мне отслеживать размер каждого?
  • Как мне определить структуру?
  • Я все делаю неправильно?

РЕДАКТИРОВАТЬ: результат должен быть непрерывный блок памяти

Ответы [ 5 ]

8 голосов
/ 03 августа 2009

Это разрешает что-то вроде

typedef struct
{
   size_t arr_size_1, arr_size_2;
   char arr_1[0/*arr_size_1 + arr_size_2*/];
} ...;

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

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

3 голосов
/ 03 августа 2009
typedef struct MyStruct_s
{
  int variable_one_size;
  void* variable_one_buf;
  int variable_two_size;
  void* variable_two_buf;
} MyStruct;

MyStruct* CreateMyStruct (int size_one, int size_two)
{
  MyStruct* s = (MyStruct*)malloc (sizeof (MyStruct));
  s->variable_one_size = size_one;
  s->variable_one_buf = malloc (size_one);
  s->variable_two_size = size_two;
  s->variable_two_buf = malloc (size_two);
}

void FreeMyStruct (MyStruct* s)
{
  free (s->variable_one_buf);
  free (s->variable_two_buf);
  free (s);
}
2 голосов
/ 03 августа 2009

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

typedef struct _serial {
  size_t sz_a;
  size_t sz_b;
  char data[1]; // "dummy" array as pointer to space at end of the struct
} serial;

serial* malloc_serial(size_t a, size_t b) {
  serial *result;
  // malloc more memory than just sizeof(serial), so that there
  // is enough space "in" the data member for both of the variable arrays
  result = malloc(sizeof(serial) - 1 + a + b);
  if (result) {
    result->sz_a = a;
    result->sz_b = b;
  }
  return result;
}

// access the "arrays" in the struct:

char* access_a(serial *s) {
  return &s->data[0];
}

char* access_b(serial *s) {
  return &s->data[s->sz_a];
}

Тогда вы можете сделать что-то вроде этого:

  serial *s = ...;
  memcpy(access_a(s), "hallo", 6);
  access_a(s)[1] = 'e';

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

1 голос
/ 03 августа 2009

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

То, что вы выберете, зависит от того, сколько данных вы храните, и от того, оптимизируете ли вы размер в выходном потоке. Часто легче сохранить размер заранее, потому что вы знаете, как велик размер буфера приема. Если вы этого не сделаете, вам придется постепенно изменять размер буфера при загрузке.

0 голосов
/ 03 августа 2009

В некотором смысле, я бы делал такие вещи, как Дэн Олсон. Тем не менее:

1) Я бы создал окончательную структуру, имея два экземпляра более простой структуры, которая имеет только один переменный массив.

2) Я бы объявил массив байтом * и использовал бы size_t для его длины.

Сказав это, я до сих пор не совсем понимаю, что вы пытаетесь сделать.

1010 * редактировать *

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

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