2013-12-16 3 views
13

В чем разница между:Дифференциация в структурах?

typedef struct part 
{ 
    int a; 
} Part; 

и

typedef struct 
{ 
    int a; 
} Part; 

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

+4

Во втором случае вы не сможете обращаться к типу как 'struct part'. Разница значительна, когда вы создаете структуру данных с привязкой (список или дерево), где 'struct part * child' должен быть членом структуры. –

+0

@SylvainDefresne Это также действительный код C++ и OP не говорят, что их интересует только C. – jrok

+1

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

ответ

19

В дополнение к Mike Seymour ответ, вот пример того, почему:

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

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

Почему? Какой смысл делать это ограничение? Почему вам не разрешено делать вторую вещь? – dfg

+4

Как мог компилятор узнать, что такое Part (во втором примере), когда он еще не определен? – EoiFirst

+0

Но тогда как компилятор может узнать, что такое 'struct part * next', когда его определение еще не завершено? – dfg

15

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

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

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

+1

Но почему вам было бы интересно, как вы можете ссылаться на него, пока вы * можете * ссылаться на него? – dfg

+0

@dfg: Вы можете ссылаться только на это в определении структуры (перед объявлением 'Part') по названию структуры - и только если она есть. –

+0

Почему? Какой смысл делать это ограничение? Почему вы не можете сами ссылаться на него? – dfg

1

И в дополнение к ответу @EoiFirst «s,

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

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

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

Смежные вопросы