Подтвердить что ты не робот

Различия в структурах?

Какая разница между:

typedef struct part 
{
   int a;
} Part;

и

typedef struct 
{
   int a;
} Part;

Я знаю, что второй является "анонимным", но отличаются ли они?

4b9b3361

Ответ 1

В дополнение к ответу Майка Сеймура, вот пример того, почему:

Связанный список, например

// 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;

Ответ 2

В обоих случаях вы определяете тип структуры и псевдоним типа Part, который ссылается на этот тип.

В первом случае вы также определяете имя структуры Part, поэтому тип структуры также может называться struct part или просто Part в С++.

Во втором случае сама структура не имеет имени (отсюда "анонимный" ) и может упоминаться только псевдонимом типа. Поскольку этот псевдоним объявляется только после определения структуры, структура не может ссылаться на себя.

Ответ 3

И кроме ответа @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

Ответ 4

@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); 

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

В общем, я бы предложил не использовать анонимные типы, если вы точно не знаете, что делаете (существует ряд случаев, когда они полностью в порядке, например, в качестве элементов реализации других типов).