Указатель на массив объявленных вперед структур в C - PullRequest
4 голосов
/ 13 января 2020

У меня есть вопрос о предварительных декларациях в C.

Код

typedef struct yhash_s t_yhash;// forward declaration
struct yhash_s {
    size_t  size_h; 
    t_yhash (*yhash)[];// pointer to array of structures
};

Как только код скомпилирован с помощью g cc, он жалуется:

ошибка: тип массива имеет неполный тип элемента 't_yhash' {aka 'struct yhash_s'}

Я понимаю, что t_yhash неизвестно (пока) и размер массива не может быть вычислен, но я спрашиваю об указателе на массив неизвестного размера, который должен быть полностью разрешен ИМХО.

Как исправить это прямое объявление и структурировать себя?

Ответы [ 2 ]

4 голосов
/ 14 января 2020

Беда в том, что деклараторы массива могут не иметь неполного типа в качестве типа элемента (C11 6.7.6.2/1). И t_yash (т. Е. struct yhash_s) не завершено до закрывающей скобки определения структуры.

Это правило также отвечает за еще одну мелочь; допустимо иметь (до завершения определения структуры):

void func( t_yhash *a );

, но не разрешено иметь:

void func( t_yhash a[] );

, даже если правило корректировки будет работать нормально, если бы не правило неполного типа элемента.

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

Но даже без этого правила ваш вариант использования может иметь другую проблему; размер указателя может быть неизвестен. Было бы законно (хотя и маловероятно на практике), чтобы «указатель на массив структуры X» имел другой размер, чем «указатель на массив структуры Y». Существует правило, что все указатели на структуру должны иметь одинаковый размер, но такого правила для указателей на массив не существует.

1 голос
/ 14 января 2020

В ответ на эту часть вашего сообщения:

Как мне исправить это предварительное объявление и структурировать себя?

Вы можете использовать void * для сохранения sh ваш массив, а затем преобразовать его обратно.

typedef struct yhash_s t_yhash;
struct yhash_s {
               size_t  size_h;
               void *yhash;
               };

static inline t_yhash (*yhash(t_yhash y))[] {
    return y.yhash;
}

Если синтаксис функции слишком тупой:

typedef t_yhash t_yhash_array[];

static inline t_yhash_array *yhash(t_yhash y) {
    return y.yhash;
}

Например:

t_yhash x[10];
t_yhash y = { 10, &x };
assert(yhash(y) == &x);
...