Подтвердить что ты не робот

Зачем использовать размер массива 1 вместо указателя?

В одном проекте с открытым исходным кодом С++ я вижу это.

struct SomeClass {
  ...
  size_t data_length;
  char data[1];
  ...
}

Каковы преимущества этого, а не использование указателя?

struct SomeClass {
  ...
  size_t data_length;
  char* data;
  ...
}

Единственное, что я могу придумать, это версия массива размера 1, пользователи не должны видеть NULL. Есть ли что-нибудь еще?

4b9b3361

Ответ 1

При этом вам не нужно выделять память в другом месте и указывать на нее указатель.

  • Нет дополнительного управления памятью
  • Доступ к памяти более вероятен в кэше памяти (намного)

Трюк состоит в том, чтобы выделить больше памяти, чем sizeof (SomeClass), и сделать для нее SomeClass*. Тогда исходная память будет использоваться вашим объектом SomeClass, а оставшаяся память может использоваться data. То есть вы можете сказать p->data[0], но также p->data[1] и т.д., Пока не нажмете на конец выделенной вами памяти.

Можно указать, что это использование приводит к поведению undefined, хотя, потому что вы объявили, что ваш массив имеет только один элемент, но обращайтесь к нему так, как если бы он содержал больше. Но реальные компиляторы действительно допускают это с ожидаемым значением, потому что у С++ нет альтернативного синтаксиса для формулировки этих средств (C99 имеет, он называется "элемент гибкого массива" там).

Ответ 2

Обычно это быстрый (и грязный?) способ избежать множественных распределений памяти и освобождения памяти, хотя он более стильный, чем С++.

То есть вместо этого:

struct SomeClass *foo = malloc(sizeof *foo);
foo->data = malloc(data_len);
memcpy(foo->data,data,data_len);

....
free(foo->data);
free(foo);

Вы делаете что-то вроде этого:

struct SomeClass *foo = malloc(sizeof *foo + data_len);
memcpy(foo->data,data,data_len);

...
free(foo);

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

Ответ 3

Обычно вы видите это как конечный элемент структуры. Тогда кто бы ни malloc структура, будет выделять все байты данных последовательно в памяти, как один блок, чтобы "следовать" структуре.

Итак, если вам нужны 16 байт данных, вы должны выделить такой экземпляр:

SomeClass * pObj = malloc(sizeof(SomeClass) + (16 - 1));

Затем вы можете получить доступ к данным, как к массиву:

pObj->data[12] = 0xAB;

И вы также можете бесплатно бесплатно скачать все материалы одним звонком.

Элемент data представляет собой массив из одного элемента по соглашению, поскольку более старые компиляторы C (и, по-видимому, текущий С++-стандарт) не допускают массив нулевого размера. Приятно продолжить обсуждение здесь: http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

Ответ 4

В вашем примере они семантически различаются.

char data[1] - допустимый массив char с одним неинициализированным элементом, выделенным в стеке. Вы можете написать data[0] = 'w', и ваша программа будет правильной.

char* data; просто объявляет указатель, который является недопустимым, пока инициализируется, чтобы указать на действительный адрес.

Ответ 5

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

  • Он фактически использует меньше памяти, потому что ему не нужно хранить сам указатель.

  • Также могут быть преимущества производительности при кешировании из-за смежности памяти.

Ответ 6

Идея этой конкретной вещи заключается в том, что остальные data вписываются в память непосредственно после структуры. Конечно, вы все равно можете это сделать.