Что значит иметь неполный массив в структуре? - PullRequest
1 голос
/ 16 января 2012

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

typedef struct {
    uint8_t type;
    struct {
        uint8_t length;
        uint8_t data[5];
    } m;
} s;

Но когда я использую uint8_t data[], что это значит?Я догадался, что это может быть то же самое, что и uint8_t *data, но это не так.Когда я пытаюсь присвоить его так:

s the_s;
uint8_t something[] = {1, 2, 3};
the_s.m.data = something;

компилятор дает мне

не может назначить объекты типа массива

Ответы [ 3 ]

3 голосов
/ 16 января 2012

Массив неполного типа в качестве последнего члена структуры - это функция C99, называемая гибкий элемент массива .

В этом выражении

the_s.m.data = something;

вы пытаетесь назначить массив, но в C массивы не могут быть назначены.

2 голосов
/ 16 января 2012

Неполный тип массива - это ссылка на местоположение, где был бы выделен первый элемент массива, но фактически не выделяет место для этого элемента. На некоторых старых компиляторах Си можно получить аналогичный эффект, объявив массив нулевого размера, хотя это никогда не было законным ни в одной «официальной» версии стандарта Си. Основное использование для таких объявлений - для структур, которые будут распределены с использованием malloc, calloc или другого подобного механизма; код, который выделяет пространство для структуры, выделит достаточно дополнительного пространства для обработки нужного количества элементов массива.

Прежде чем незавершенные объявления массива стали легальными в C, обычным обходным решением было объявить массив размера 1, а затем вычесть один из числа элементов, добавляемых в структуру. Например:

struct {
  int this,that,whatever;
  char name[1];
} MYSTRUCT;

void test(char *new_name, int new_name_length)
{
  MYSTRUCT *ms = malloc(sizeof(MYSTRUCT)+new_name_length-1);
  memcpy(ms->name, new_name, new_name_length);
}

Однако у этого подхода есть несколько неприятных аспектов:

  1. Нет гарантии, что используемая формула не выделит лишнего дополнительного пространства. Например, если sizeof (int) == 4, sizeof (mystruct) может быть дополнен до 20 байтов из-за требований int-alignment. Если name_length равно четырем, общий размер должен быть 24 байта, но malloc запросит 27.
  2. Поскольку максимальный допустимый индекс для массива меньше размерного размера или выделенного пространства, доступ к `ms-> name [i]` для любого значения `i`, отличного от нуля, технически будет неопределенным поведением. Таким образом, было бы совершенно законно, если компилятор оптимизировал `ms-> name [i]` как `ms-> name [0]`. На практике я не удивлюсь, если каждый существующий опубликованный компилятор C будет воздерживаться от выполнения этой оптимизации при подписке одноэлементного массива в конце структуры с косвенным доступом (потому что является ли общая реализация структуры struct hack 'легален, его использует много производственного кода.

Если бы компиляторы C просто не включили код для отклонения массивов нулевого размера, и стандарт указал, что максимальное значение индекса для любого массива (unsigned int) (size-1), взломать структуру было бы намного чище , К сожалению, стандарт не был написан таким образом.

2 голосов
/ 16 января 2012

Ваше предположение, что data[] совпадает с *data, просто неверно.

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

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