2009-03-09 4 views
21

EDIT: видимо, некоторые из них не разрешены/изменены в разных стандартах C. Для моей гипотетической выгоды, давайте притвориться, что мы используем gcc test.c без стандартных или предупреждающих опций.массивы нулевой длины против указателей

В частности, я изучаю особенности нижнего капота. Я добавил свое понимание. Я прав?

char **c1; //Size for a pointer is allocated on the stack. sizeof(c1) == sizeof(void*) 
char *c2[0]; //Nothing is allocated on the stack. sizeof(c2) == 0 

Есть ли другая разница между этими двумя случаями, о которых я не знаю (помимо sizeof)?

struct a { 
    int i; 
    char c[0]; //sizeof(a) is sizeof(int)? a.c == (&i)+1? 
}; 

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

struct b { 
    char *c[0] //sizeof(b) is 0? where does c point? 
}; 

int j; 
struct b myb; //myb.c == (&j)+1 == $esp? 

Кроме того, как адрес массива нулевой длины, если известно, пространство для его указателя никогда не выделяется в любом месте? Я предполагаю, что так же известен адрес регулярного массива, но сейчас я изо всех сил пытаюсь обдумать его.

+0

См. Также [здесь] (http://stackoverflow.com/a/14643530/912144). – Shahbaz

ответ

9

ISO C запрещает 0 -length массивы.

char **c1; 

Это определяет объект c1 в указатель на указатель-на-полукокса типа.

char *c2[0]; 

Это ошибка компиляции. Не допускается. Не в C, а не на C++.

struct a { 
    int i; 
    char c[0]; //sizeof(a) is sizeof(int)? a.c == (&i)+1? 
}; 

Ошибка, как отмечалось ранее, размер массива должен быть больше нуля.

struct a { 
    int i; 
    char c[1]; 
}; 

Также известен как -структуры взломать. Злоупотребление в низкоуровневом коде практически для всех ОС - Linux, Windows.

C99 действительно дает нам sizeless массив более известный как член гибкого массива:

struct a { 
    int i; 
    char c[]; /* note: no size */ 
}; 
+0

Ahh, но если вы перепечатали его ias char c []; и был c как последний член a, он был бы законным с C99. Whee! – MSN

+0

@MSN - добавлено, что за несколько секунд до опубликования вашего комментария :) – dirkgently

+0

Это не всегда ошибка времени компиляции. gcc только предупреждает об этом, и только с флажками -Wall и -pedantic. – mkb

12

Единственный раз, когда я когда-либо видел нулевой длины массивов фактически используется, когда вы хотите иметь переменную структуру длины ,

Как и в этом примере взяты из here

struct line { 
     int length; 
     char contents[0]; 
    }; 

    struct line *thisline = (struct line *) 
     malloc (sizeof (struct line) + this_length); 
    thisline->length = this_length; 

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

Если вы делаете sizeof в вышеприведенной структуре, он не содержит места для содержимого. Я не уверен, что это когда-либо превращало его в стандарт, он дает предупреждения для разных компиляторов.

+0

Благодарим вас за разъяснение практического использования этой идиомы. Правильно ли это, если вы пытаетесь понять код, который использует его. –

1

От стандарта C99 (7.20.3), имеем дело с функциями распределения:

Каждое такое распределение будет давать указатель на объект непересекающихся из любого другого объекта.

[...]

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

Другими словами, в случае объявления b на стеке без инициализатора (где b является еще c объявлен как c[] вместо c[0]), фактический размер b в терминах пространства фактически используемых будет> 0, так как вы не можете получить доступ к какой-либо части b. Если он назначен через malloc, он будет либо возвращен как 0, либо как некоторая уникальная ценность, к которой нельзя получить доступ (если вы используете).

+0

Несомненно, что в разделе стандарта применяется только malloc? Я не могу видеть актуальность предыдущей части этого ответа. «Фактически используемое пространство будет> 0, так как вы не можете получить доступ к какой-либо части b» –

2

Здесь вы можете получить ответы от GCC docs. Но основное внимание уделяется теме наличия массива нулевой длины в качестве последних членов структуры. Он не дает прямых ответов относительно sizeof.

(Как было четко другими, нулевой длины массивы не в стандартном C, но они были в GNU C.)

0

Массив не может иметь нулевой размер.

ISO 9899:2011 6.7.6.2: 

If the expression is a constant expression, it shall have a value greater than zero. 

Вышеприведенный текст является истинным как для простого массива (§1), так и для VLA (§5). Это нормативный текст в стандарте C. Компилятору не разрешено реализовать его по-разному.

gcc -std = c99 -pedantic дает предупреждение для этого.

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