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

13

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

typedef struct part 
{
   int a;
} Part;

и

typedef struct 
{
   int a;
} Part;

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

  • 4
    Во втором случае вы не сможете ссылаться на тип как на struct part . Разница существенна, когда вы создаете struct part *child структуру данных (список или дерево), где struct part *child должна быть членом структуры.
  • 0
    @SylvainDefresne Это также допустимый код C ++, и OP не сказал, что они заинтересованы только в C.
Показать ещё 2 комментария
Теги:
data-structures

4 ответа

19
Лучший ответ

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

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

// 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;
  • 0
    Зачем? Какой смысл делать это ограничение? Почему тебе не разрешено делать второе?
  • 4
    Как мог компилятор знать, что такое Part (во втором примере), когда он еще не определен?
Показать ещё 11 комментариев
15

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

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

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

  • 1
    Но почему вас волнует, как вы можете ссылаться на него, если вы можете ссылаться на него?
  • 0
    @dfg: Вы можете ссылаться на него только в определении структуры (до объявления Part ) по имени структуры - и только если оно есть.
Показать ещё 2 комментария
1

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

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню