Какая разница между:
typedef struct part
{
int a;
} Part;
и
typedef struct
{
int a;
} Part;
Я знаю, что второй является "анонимным", но отличаются ли они?
Какая разница между:
typedef struct part
{
int a;
} Part;
и
typedef struct
{
int a;
} Part;
Я знаю, что второй является "анонимным", но отличаются ли они?
В дополнение к ответу Майка Сеймура, вот пример того, почему:
Связанный список, например
// this works
typedef struct part {
struct part *next;
} Part;
// this doesn't work
typedef struct {
struct Part *next;
} Part;
// neither this
typedef struct {
Part *next;
} Part;
В обоих случаях вы определяете тип структуры и псевдоним типа Part
, который ссылается на этот тип.
В первом случае вы также определяете имя структуры Part
, поэтому тип структуры также может называться struct part
или просто Part
в С++.
Во втором случае сама структура не имеет имени (отсюда "анонимный" ) и может упоминаться только псевдонимом типа. Поскольку этот псевдоним объявляется только после определения структуры, структура не может ссылаться на себя.
И кроме ответа @EoiFirst,
typedef struct part
{
int a;
struct part *next;
} Part;
Это верно, потому что next
является указателем до struct part
, поэтому он имеет размер типа указателя.
C - это типизированный язык, поэтому компилятор знает тип next
, а после struct part
полностью определен, он сможет определить, что приведенный ниже код действителен. Он знает, что next
является указателем на struct part
, который имеет поле int a
.
void test(struct part *p) {
if (p != NULL && p->next != NULL) {
printf("%d\n", p->next->a); // this is valid
}
}
Вы можете объявить
typedef struct part
{
int a;
void *next;
} Part;
Размер struct part
по-прежнему будет таким же, как указано выше. Теперь next
является указателем на что угодно, а код с test()
выше компилируется с ошибкой.
warning: dereferencing 'void *' pointer
error: request for member 'a' in something not a structure or union
Вам нужно написать printf("%d\n", ((struct part *) p->next)->a);
Кроме того, вы не сможете объявить это,
typedef struct part
{
int a;
struct part nested;
} Part;
Вы получите ошибку компилятора.
error: field 'nested' has incomplete type
@MikeSeymur и другие дали отличные ответы. Я хочу добавить важный момент, который никто не указал явно.
В больших проектах важно сохранить заголовки минимальными и избегать #include
-в других заголовков, если это абсолютно необходимо.
Предположим, что ваша структура определена в каком-то файле заголовка part.h
. Определенный тип структуры Part
позволяет другим, кто использует ваш код, пропустить #include "part.h" с помощью так называемой "прямой декларации":
//file foo.h knows struct Part "by name only"
struct Part;
void foo(struct Part* p); //in pure C, works for C++ too
void bar(Part* p); //in C++
В случае анонимной структуры файл foo.h принудительно на #include файл part.h
//file foo.h forced to #include part.h because "part" is typedef of anonymous type
#include "part.h"
void foo(part* p);
В устаревшем коде довольно часто эти анонимные типы приводят к ситуации, когда каждый заголовок включает в себя так много других заголовков, что обслуживание и повторное использование кода становятся кошмаром.
В общем, я бы предложил не использовать анонимные типы, если вы точно не знаете, что делаете (существует ряд случаев, когда они полностью в порядке, например, в качестве элементов реализации других типов).