Допускается ли typedef перед определением - PullRequest
4 голосов
/ 07 мая 2020

Минимальный код:

// foo.h

typedef struct foo_s foo_t;

struct foo_s {
  foo_t* next;
};

iwyu настаивает, что я пересылаю объявление struct foo_s перед I typedef его foo_t.

Вывод:

$ iwyu -c foo.h 

foo.h should add these lines:
struct foo_s;

foo.h should remove these lines:

The full include-list for foo.h:
struct foo_s;
---

Это верно для разных версий iwyu, включая более новые версии с добавлением -Xiwyu --no_fwd_decls.

Это ошибка в iwyu или стандарт C требует, чтобы я определил тип перед typedef?

Ответы [ 3 ]

4 голосов
/ 07 мая 2020

требует ли стандарт C, чтобы я определял тип перед typedef?

Это не так. Стандартный набор слов выглядит следующим образом:

6.7.2.3 Теги

7 Объявление формы

      struct-or-union identifier ;

определяет структуру или тип объединения и объявляет идентификатор как тег этого типа.

8 Если спецификатор типа в форме

      struct-or-union identifier

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

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


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

void bar(struct foo);

struct foo {
    char c;
};

void bar(struct foo f) {}

Так получилось, что первое объявление bar объявляется с типом, уникальным для его параметра. список. Начальное объявление struct foo не того же типа, что использовалось в более позднем определении функции. Таким образом, код не будет компилироваться соответствующим компилятором C. Объявление структуры в отдельной строке перед первым объявлением функции решает эту проблему.

1 голос
/ 07 мая 2020

Этот C11 Draft Standard совершенно ясно дает понять, что вы можете 'пересылать объявление' a typedef struct... в качестве примера, который очень похож на ваш код:

6.7.2.3 Теги ... 11 В следующей альтернативной формулировке используется механизм typedef :

typedef struct tnode TNODE;
struct tnode {
    int count;
    TNODE *left, *right;
};
TNODE s, *sp; 
0 голосов
/ 07 мая 2020

Это ошибка. Кажется, что typedef для структуры рассматривается так же, как typedef для перечисления.

Для перечислений вы не можете использовать неполный тип в определении typedef

Из стандарта C Standard (6.7.2.3 Теги)

3 Спецификатор типа в форме

enum identifier 

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

Так, например, такой typedef

typedef enum E AnotherE;

enum E { N };

недействителен, в то время как этот typedef

enum E { N };

typedef enum E AnotherE;

действителен.

Для структур, вы можете использовать неполный тип в определении typedef.

8 Если спецификатор типа в форме

struct-or-union identifier

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

...