Код без typedef (и он работает):
struct Node {
int data;
struct Node *next;
struct Node *prev;
};
Я пытаюсь создать код с использованием typedef для структуры «Узел» в двусвязном списке, но это не работает:
typedef struct {
int data;
Node *next;
Node *prev;
} Node;
Есть ли способ обойти это с помощью typedef?





Внутри typedef определяемый тип еще не известен, поэтому вам необходимо ввести и использовать тег структуры:
typedef struct Node_tag {
int data;
struct Node_tag *next;
struct Node_tag *prev;
} Node;
Node_tag - это структурный тег из-за того, где он введен (а не из-за части имени «_tag»). Это не тип сам по себе, а только комбинация, поскольку struct Node_tag является типом, который может использоваться для членов структуры.
Впоследствии, когда typedef завершен, тип Node был определен.
Чтобы уточнить, возможно использование второго typedef как typedef struct Node_tag NodeToo;. Это демонстрирует, что тип struct Node_tag также можно использовать. Вот почему я предпочитаю использовать фрагмент имени "_tag", чтобы было понятно, что используется.
Вы можете использовать предварительное объявление структуры
typedef struct sNode Node; // this is a typedef and a declaration of the struct
struct sNode{
int data;
Node *next;
Node *prev;
};
Таким образом, Node известен (но не определен) в определении вашего struct.
Его можно сжать, как это делает Юннош. Но тогда вам нужно использовать нотацию struct Name внутри вашего объявления.
Таким образом, можно уже использовать имя typedefed, также необходимо предварительное объявление, если у вас есть некоторые циклические зависимости в ваших структурах.
Также можно использовать имя структуры в качестве определения типа:
typedef struct Node Node;
struct Node{
int data;
Node *next;
Node *prev;
};
Лично я предпочитаю первый стиль, мне он кажется «более понятным», но во втором примере нет ничего плохого, если только компилятор не из достандартной эпохи (до 1989 года).
Как указал Йенс Густедт, первый стиль может быть несовместимым, если он включен в C++.
Так что, возможно, мне стоит изменить свое предпочтение на первое.
@JHBonarius Хорошая ссылка, я добавил ее в свою библиотеку ссылок SO.
Нет особых причин использовать struct sNode. struct Node, то есть тот же идентификатор тега, что и для typedef.
@JensGustedt Я знаю, что часто используется одно и то же имя со структурой и без нее. Но я думаю, что это «грязно», и есть некоторые правила, требующие разных имен. Но я не знаю, насколько они распространены.
@JensGustedt Кажется, с этой практикой даже могут быть проблемы. Спасибо JHBonarius
@KamiKaze Но эти проблемы были с предстандартные компиляторы C. Для нового кода это не должно быть проблемой. С typedef struct Foo {} Foo; никогда не сталкивался.
Чтобы поместить это в контекст, предварительный стандарт относится к компиляторам, которые не удосужились стать соответствующими стандарту около 30 лет. И нет, это не грязный, так и должно быть. Наличие разных имен для одного и того же типа очень сбивает с толку, и определение типа одного и того же идентификатора - это то, что нужно сделать, если вы хотите, чтобы заголовок был совместим с C++.
@JensGustedt Я включил это в свой ответ, но это все же C, и это действительно так. Существуют и другие вещи, которые являются совершенно допустимыми для C, которые нарушают работу компилятора C++ (без преобразования malloc afaik), поэтому совместимость с C++ - это хорошо (а иногда и обязательно), но сама по себе не является показателем для кода C.
@KamiKaze, поэтому я сказал "совместимость с заголовком".
Внутри структуры вы действительно должны использовать типы, которые уже известны компилятору. Способ соответствовать этому правилу в вашем случае - используйте тип struct Node * после объявления typedef struct Node. В этом случае, даже если тип struct Node не полностью определен, когда компилятор обнаруживает его внутри структуры, имя известно, и компилятор знает размер указателя (для резервирования в памяти), поэтому у него нет причин жаловаться!
Более того, также принято использовать то же имя для типа, что и после struct: вы можете использовать Node для обоих.
Вот мое предлагаемое решение:
typedef struct Node {
int data;
struct Node *next;
struct Node *prev;
} Node;
Несмотря на поддержку, я не считаю хорошей практикой давать структуре то же имя, что и тип. Не рекомендуется для совместимости (с древними компиляторами
@Laurent Хорошо, спасибо! К сожалению, я выбрал другой ответ. Тем не менее, ваше объяснение очень помогает, и я поддержал ваш ответ :-)
@WealthyPlayer Добро пожаловать, спасибо за ваш голос. Мой ответ действительно был немного запоздалым, но я постарался, чтобы он был полным. Рад видеть, что это было полезно!
@WealthyPlayer Как правило, вы не привязаны к своему первому решению по выбранному ответу. Вы должны выбрать то, что считаете подходящим.
@Kami Отметил :-D Извините за очень поздний ответ на комментарий.