Зачем использовать размер массива 1 вместо указателя?
В одном проекте с открытым исходным кодом С++ я вижу это.
struct SomeClass {
...
size_t data_length;
char data[1];
...
}
Каковы преимущества этого, а не использование указателя?
struct SomeClass {
...
size_t data_length;
char* data;
...
}
Единственное, что я могу придумать, это версия массива размера 1, пользователи не должны видеть NULL. Есть ли что-нибудь еще?
Ответы
Ответ 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
вписываются в память непосредственно после структуры. Конечно, вы все равно можете это сделать.