Объявление неструктурированного массива в структуре
Почему C позволяет это:
typedef struct s { int arr []; } s;
где массив arr
размер не указан?
2 ответа
Это особенность C99, называемая гибкими массивами, основная функция которой заключается в том, чтобы разрешить использование массива переменной длины, например, функций внутри структуры и R. В этом ответе на другой вопрос о гибких элементах массива приведен список преимуществ использования гибких массивов над указателями. Проект стандарта С99 в разделе 6.7.2.1
В параграфе 16 спецификаторов структуры и объединения говорится:
В особом случае последний элемент структуры с более чем одним именованным элементом может иметь тип неполного массива; это называется членом гибкого массива. В большинстве случаев член гибкого массива игнорируется. В частности, размер структуры такой, как если бы элемент гибкого массива был опущен, за исключением того, что он может иметь больше заполняющего отступа, чем это может означать упущение. [...]
Так что, если у вас был s*
Вы должны выделить пространство для массива в дополнение к пространству, требуемому для структуры, обычно у вас будут другие члены в структуре:
s *s1 = malloc( sizeof(struct s) + n*sizeof(int) ) ;
На самом деле проект стандарта содержит поучительный пример в пункте 17:
ПРИМЕР После объявления:
struct s { int n; double d[]; };
структура структура
s
имеет гибкий член массиваd
, Типичный способ использовать это:int m = /* some value */; struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
и предполагая, что вызов
malloc
успешно, объект, на который указываетp
ведет себя в большинстве случаев так, как будтоp
был объявлен как:struct { int n; double d[m]; } *p;
(существуют обстоятельства, при которых эта эквивалентность нарушается; в частности, смещения члена
d
может быть не то же самое).
Вы, вероятно, ищете гибкие массивы в C99. Гибкие члены массива являются членами неизвестного размера в конце структуры / объединения.
В особом случае последний элемент структуры с более чем одним именованным элементом может иметь тип неполного массива; это называется членом гибкого массива. В большинстве случаев член гибкого массива игнорируется. В частности, размер структуры такой, как если бы элемент гибкого массива был опущен, за исключением того, что он может иметь больше завершающего дополнения, чем подразумевает это упущение.
Вы также можете посмотреть на причину взлома структуры в первую очередь.
Не ясно, законно ли это или портативно, но это довольно популярно. Реализация техники может выглядеть примерно так:
#include <stdlib.h>
#include <string.h>
struct name *makename(char *newname)
{
struct name *ret =
malloc(sizeof(struct name)-1 + strlen(newname)+1);
/* -1 for initial [1]; +1 for \0 */
if(ret != NULL) {
ret->namelen = strlen(newname);
strcpy(ret->namestr, newname);
}
return ret;
}
Эта функция выделяет экземпляр структуры имени с размером, отрегулированным так, чтобы поле namestr могло содержать запрошенное имя (а не только один символ, как предполагает объявление структуры).
Несмотря на свою популярность, техника также несколько печально известна - Деннис Ритчи назвал ее "необоснованной болтовней с реализацией C". Официальное толкование показало, что оно НЕ строго соответствует стандарту C, хотя, похоже, оно работает при всех известных реализациях. Компиляторы, которые тщательно проверяют границы массивов, могут выдавать предупреждения.