массивы нулевой длины и указатели - PullRequest
21 голосов
/ 09 марта 2009

РЕДАКТИРОВАТЬ: очевидно, что это не разрешено / изменилось в различных стандартах 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?

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

Ответы [ 5 ]

12 голосов
/ 09 марта 2009

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

Как в этом примере взято из здесь

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

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

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

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

9 голосов
/ 09 марта 2009

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

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]; 
};

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

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

struct a {
  int i;
  char c[]; /* note: no size */ 
};
2 голосов
/ 24 декабря 2011

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

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

1 голос
/ 09 марта 2009

Из стандарта C99 (7.20.3), касающегося функций распределения:

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

[...]

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

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

0 голосов
/ 06 марта 2016

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

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 выдает предупреждение за это.

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