2010-11-23 3 views
4

Что означает следующее?Объявление вектора нулевого размера

struct foo 
{ 
... 
char bar[0]; // Zero size??? 
}; 

Я попросил своих коллег, и они сказали мне, что это то же самое, как написание void* bar.

Насколько я знаю, C-указатель представляет собой всего лишь 4 байтовую переменную (по крайней мере, на 32-битной машине). Как компилятор знает, что bar [0] является указателем (и, следовательно, 4 байта)? Это просто синтаксический сахар?

ответ

5

Ваши коллеги солгали. (Возможно, не намеренно, хотя и не злитесь на них или что-то в этом роде.)

Это называется гибким элементом массива, а в C99 - char bar[];, а в C89 - char bar[1];, а некоторые компиляторы напишите как char bar[0];. В принципе, вы только использовать указатели на структуру, и выделить их все с количеством дополнительного пространства в конце:

const size_t i = sizeof("Hello, world!"); 
struct foo *p = malloc(offsetof(struct foo, bar) + i); 
memcpy(p->bar, "Hello, world!", i); 
// initialize other members of p 
printf("%s\n", p->bar); 

Таким образом, p->bar хранит строки, размер которого не ограничен объявлении массива, но который все еще выполняется в том же распределении, что и остальная часть struct (вместо того, чтобы элемент был char * и ему нужно было два malloc s и два free s для его настройки).

+0

А теперь я понимаю. Таким образом, экземпляр структуры содержится в области непрерывной памяти. Если бы бар был указателем, он указывал бы на другой фрагмент памяти. Таким образом, гибкие массивы позволяют копировать структуру с помощью одной memcopy, например. Я обнаружил, что структура в ядре Linux и на самом деле одна memcopy используется для копирования из пространства ядра в пространство пользователя. – Emiliano 2010-11-23 12:31:16

+1

@happy_emi - В дополнение к одному «memcpy» (который является большим плюсом) он также принимает только один «malloc» (который может быть относительно дорогим, особенно если это тот объект, в котором вы их много) , – 2010-11-23 12:39:12

0

Это должна быть ошибка времени компилятора! Только динамически распределенные массивы могут быть выделены с размером 0.

+0

Некоторые (ленивые?) Компиляторы позволят людям объявлять гибкие элементы массива как `char bar [0];` перед тем, как C99 стандартизовал синтаксис `char bar [];`. Так что это, вероятно, не ошибка. – 2010-11-23 10:50:15

0

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

Это подозрение, а не знание. :)

Это не то, как вы могли бы что-либо сделать, хотя ... Если они хотят указателя, то они должны использовать указатель. Если они не могут сказать вам, почему это так, этого не должно быть.

+0

Я сам подумал о лейбле. Но поле объявлено в нижней части строения – Emiliano 2010-11-23 13:12:53

3

Ответ Криса правильный, но я бы, вероятно, выделил объект несколько иначе.

int n = ...; // number of elements you want 
struct foo *p = malloc(offsetof(struct foo, bar[n])); 

затем итерацию над ним с

for (int i = 0; i < n; ++i) { 
    p->bar[i] = ...; 
} 

Ключевым моментом является то, что ответ Криса работает с sizeof(char)==1, но для другого типа, вы должны явно умножить на sizeof *bar.

Смежные вопросы