typedef struct vs struct definitions [duplicate]

To pytanie ma już odpowiedź tutaj:

Jestem początkującym programistą w C, ale zastanawiałem się, jaka jest różnica między używaniem typedef podczas definiowania struktury a nie używaniem typedef. Wydaje mi się, że naprawdę nie ma różnicy, osiągają to samo.

struct myStruct{
    int one;
    int two;
};

Vs.

typedef struct{
    int one;
    int two;
}myStruct;
Author: OmG, 2009-11-04

12 answers

Wspólny idiom używa obu:

typedef struct X { 
    int x; 
} X;

Są to różne definicje. Aby uczynić dyskusję jaśniejszą podzielę zdanie:

struct S { 
    int x; 
};

typedef struct S S;

W pierwszej linii definiujesz identyfikator S w przestrzeni nazw struktury (Nie w sensie C++). Można go użyć i zdefiniować zmienne lub argumenty funkcji nowo zdefiniowanego typu, definiując typ argumentu jako struct S:

void f( struct S argument ); // struct is required here

Druga linia dodaje Alias typu S w globalnej przestrzeni nazw w ten sposób można po prostu napisać:

void f( S argument ); // struct keyword no longer needed

Zauważ, że ponieważ obie przestrzenie nazw identyfikatorów są różne, zdefiniowanie S zarówno w strukturach, jak i w przestrzeniach globalnych nie jest błędem, ponieważ nie jest to ponowne zdefiniowanie tego samego identyfikatora, ale raczej utworzenie innego identyfikatora w innym miejscu.

Aby różnica była jaśniejsza:

typedef struct S { 
    int x; 
} T;

void S() { } // correct

//void T() {} // error: symbol T already defined as an alias to 'struct S'

Można zdefiniować funkcję o tej samej nazwie struktury, ponieważ identyfikatory są przechowywane w różnych przestrzeniach, ale nie można zdefiniować funkcja o tej samej nazwie co typedef, gdy te identyfikatory zderzają się.

W C++ jest nieco inaczej, ponieważ zasady lokalizowania symbolu uległy subtelnym zmianom. C++ nadal zachowuje dwie różne przestrzenie identyfikatorów, ale w przeciwieństwie do C, gdy zdefiniujesz tylko symbol w przestrzeni identyfikatorów klasy, nie musisz podawać słowa kluczowego struct/class: {]}

 // C++
struct S { 
    int x; 
}; // S defined as a class

void f( S a ); // correct: struct is optional

Jakie zmiany są regułami wyszukiwania, a nie gdzie są zdefiniowane identyfikatory. Kompilator przeszukuje globalną tabela identyfikatorów i po tym, jak S nie zostanie znaleziona, będzie wyszukiwać S wewnątrz identyfikatorów klasy.

Przedstawiony wcześniej kod zachowuje się w ten sam sposób:

typedef struct S { 
    int x; 
} T;

void S() {} // correct [*]

//void T() {} // error: symbol T already defined as an alias to 'struct S'

Po zdefiniowaniu funkcji S w drugiej linii, struktura s nie może być rozwiązana automatycznie przez kompilator i aby utworzyć obiekt lub zdefiniować argument tego typu, musisz wrócić do słowa kluczowego struct:

// previous code here...
int main() {
    S(); 
    struct S s;
}
 820
Author: David Rodríguez - dribeas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-04 20:40:30

struct i typedef to dwie bardzo różne rzeczy.

Słowo kluczowe struct jest używane do definiowania lub odwoływania się do typu struktury. Na przykład to:

struct foo {
    int n;
};

Tworzy nowy typ o nazwie struct foo. Nazwa foo jest znacznikiem ; ma znaczenie tylko wtedy, gdy jest bezpośrednio poprzedzone słowem kluczowym struct, ponieważ znaczniki i inne identyfikatory są w odrębnych przestrzeniach nazw . W języku C++ pojęcie to jest podobne, ale znacznie bardziej ograniczone niż w języku C++.]}

A typedef, pomimo nazwy, nie definiuje nowego typu; tworzy jedynie nową nazwę dla istniejącego typu. Na przykład:

typedef int my_int;

my_int to nowa nazwa dla int; my_int i int dokładnie tego samego typu. Podobnie, biorąc pod uwagę powyższą definicję struct, można napisać:

typedef struct foo foo;

Typ ma już nazwę, struct foo. Deklaracja typedef nadaje temu samemu typowi nową nazwę, foo.

Składnia pozwala połączyć struct i typedef w jeden "deklaracja": {]}

typedef struct bar {
    int n;
} bar;

To jest powszechny idiom. Teraz możesz odnosić się do tego typu struktury albo jako struct bar, albo po prostu jako bar.

Zauważ, że nazwa typedef jest widoczna dopiero na końcu deklaracji. Jeśli struktura zawiera wskaźnik do siebie, musisz użyć wersji struct, aby się do niej odwołać:

typedef struct node {
    int data;
    struct node *next; /* can't use just "node *next" here */
} node;

Niektórzy programiści będą używać odrębnych identyfikatorów dla znacznika struct i dla nazwy typedef. Moim zdaniem nie ma ku temu powodu; korzystanie z ta sama nazwa jest całkowicie legalna i wyjaśnia, że są tego samego typu. Jeśli musisz użyć różnych identyfikatorów, przynajmniej użyj spójnej konwencji:

typedef struct node_s {
    /* ... */
} node;

(osobiście wolę pominąć typedef i odnieść się do typu jako struct bar. typedef oszczędź trochę pisania, ale ukrywa to fakt, że jest to typ struktury. Jeśli chcesz, aby Typ był nieprzezroczysty, może to być dobra rzecz. Jeśli kod klienta będzie odnosił się do członka n po nazwie, to nie jest nieprzezroczysty; jest widoczny strukturą, a moim zdaniem sensowne jest nazywanie jej strukturą. Ale wielu inteligentnych programistów nie zgadza się ze mną w tej kwestii. Bądź przygotowany na przeczytanie i zrozumienie kodu napisanego w obie strony.)

(C++ ma inne zasady. Po podaniu deklaracji struct blah, możesz odnosić się do typu jako tylko blah, nawet bez typedef. Korzystanie z typedef może sprawić, że Twój kod C będzie trochę bardziej podobny do C++ - Jeśli uważasz, że to dobra rzecz.)

 93
Author: Keith Thompson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-15 18:02:29

Inną różnicą, której nie zauważono, jest to, że nadanie struct nazwy (np. struct myStruct) pozwala również na dostarczenie deklaracji forward struktury. Więc w jakimś innym pliku mógłbyś napisać:

struct myStruct;
void doit(struct myStruct *ptr);

Bez konieczności dostępu do definicji. Polecam połączyć dwa przykłady:

typedef struct myStruct{
    int one;
    int two;
} myStruct;

Daje to wygodę bardziej zwięzłej nazwy typedef, ale nadal pozwala na użycie pełnej nazwy struktury, jeśli zajdzie taka potrzeba.

 85
Author: R Samuel Klatchko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-28 16:34:36

W C (nie C++), musisz zadeklarować zmienne struct takie jak:

struct myStruct myVariable;

Aby móc używać myStruct myVariable; zamiast tego, możesz typedef STRUCT:

typedef struct myStruct someStruct;
someStruct myVariable;

Możesz połączyć struct definicję i typedef s W Jednym oświadczeniu, które deklaruje anonimowe struct i typedefS to.

typedef struct { ... } myStruct;
 50
Author: Mehrdad Afshari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-04 17:25:53

Jeśli używasz struct Bez typedef, zawsze będziesz musiał napisać

struct mystruct myvar;

To nielegalne pisać

mystruct myvar;

Jeśli używasz typedef nie potrzebujesz już prefiksu struct.

 24
Author: RED SOFT ADAIR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-10 13:36:08

W języku C słowa kluczowe określające typ struktur, związków i wyliczeń są obowiązkowe, tzn. zawsze musisz przedrostek nazwy typu (jego znacznik ) z struct, union lub enum w odniesieniu do typu.

Możesz pozbyć się słów kluczowych za pomocą typedef, która jest formą ukrywania informacji, ponieważ rzeczywisty typ obiektu nie będzie już widoczny podczas deklarowania go.

Dlatego jest to zalecane (patrz np. Linux Kernel coding style guide , Rozdział 5) robić to tylko wtedy, gdy w rzeczywistości chcesz ukryć te informacje, a nie tylko zapisać kilka naciśnięć klawiszy.

Przykładem kiedy należy użyć typedef jest nieprzezroczysty typ, który jest używany tylko z odpowiednimi funkcjami/makrami dostępowymi.

 22
Author: Christoph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-05 15:39:17

Różnica pojawia się, gdy używasz struct.

Pierwszy sposób, który musisz zrobić:

struct myStruct aName;

Drugi sposób pozwala usunąć słowo kluczowe struct.

myStruct aName;
 5
Author: jjnguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-04 17:26:47

Nie można używać deklaracji forward z typedef struct.

Sam struct jest typem anonimowym, więc nie masz rzeczywistej nazwy do zadeklarowania.

typedef struct{
    int one;
    int two;
} myStruct;

Taka deklaracja forward nie zadziała:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types
 5
Author: Yochai Timmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-10 13:35:09

typedef, podobnie jak w przypadku innych konstrukcji, jest używany do nadania typowi danych nowej nazwy. W tym przypadku najczęściej robi się to w celu uczynienia kodu czystszym:

struct myStruct blah;

Vs.

myStruct blah;
 4
Author: RC.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-04 17:42:55

Poniższy kod tworzy anonimową strukturę z aliasem myStruct:

typedef struct{
    int one;
    int two;
} myStruct;

Nie można odwoływać się do niej bez aliasu, ponieważ nie określa się identyfikatora struktury.

 4
Author: Wronski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-10 13:35:40

Widzę, że pewne wyjaśnienia są w porządku w tej sprawie. C i c++ nie definiują typów inaczej. C++ był pierwotnie niczym więcej niż dodatkowym zestawem includes na szczycie C.

Problem, jaki mają dziś praktycznie wszyscy programiści C/C++, polega na tym, że a) uniwersytety nie uczą już podstaw i B) ludzie nie rozumieją różnicy między definicją a deklaracją.

Jedynym powodem istnienia takich deklaracji i definicji jest to, że linker może obliczyć przesunięcia adresów do pól w strukturze. To dlatego większość ludzi ucieka od kodu, który jest faktycznie napisany nieprawidłowo - ponieważ kompilator jest w stanie określić adresowanie. Problem pojawia się, gdy ktoś próbuje zrobić coś z góry, jak Kolejka, lub powiązana lista, lub piggying-wspieranie struktury O / s.

Deklaracja zaczyna się od 'struct', definicja zaczyna się od 'typedef'.

Ponadto struktura ma etykietę deklaracji forward I zdefiniowaną Etykietę. Większość ludzi Nie wiem tego i użyj etykiety deklaracji forward jako etykiety definiującej.

Źle:

struct myStruct
   {
   int field_1;
   ...
   };

Właśnie użyli deklaracji forward do oznaczenia struktury - więc teraz kompilator jest tego świadomy-ale nie jest to rzeczywisty zdefiniowany Typ. Kompilator może obliczyć adresowanie - ale nie tak miało być użyte, z powodów, które zaraz pokażę.

Ludzie, którzy używają tej formy deklaracji, muszą zawsze umieszczać "struct" w praktycznie każdym nawiązaniu do niej-- bo to nie jest oficjalny nowy typ.

Zamiast tego, każda struktura, która się nie odwołuje, powinna być zadeklarowana i zdefiniowana tylko w ten sposób:

typedef struct
   {
   field_1;
   ...
   }myStruct;

Teraz jest to rzeczywisty typ, A kiedy jest używany, możesz użyć at jako 'myStruct' bez konieczności poprzedzania go słowem 'struct'.

Jeśli chcesz mieć zmienną wskaźnika do tej struktury, Dołącz dodatkową Etykietę:

typedef struct
   {
   field_1;
   ...
   }myStruct,*myStructP;

Teraz masz zmienną wskaźnika do tej struktury, niestandardową do niej.

Do przodu Deklaracja--

Oto fantazyjne rzeczy, jak działa deklaracja forward. Jeśli chcesz utworzyć typ, który odnosi się do samego siebie, np. do połączonej listy lub elementu queue, musisz użyć deklaracji forward. Kompilator nie bierze pod uwagę zdefiniowanej struktury, dopóki nie dojdzie do średnika na samym końcu, więc jest zadeklarowana przed tym punktem.

typedef struct myStructElement
   {
   myStructElement*  nextSE;
   field_1;
   ...
   }myStruct;

Teraz kompilator wie, że chociaż nie wie jeszcze, czym jest cały Typ, nadal może odwoływać się do niego za pomocą / align = "left" /

Proszę poprawnie zadeklarować i wpisać swoje struktury. Właściwie to jest powód.

 3
Author: CodeGuru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-12 18:30:36

W tym drugim przykładzie pomija się słowo kluczowe struct podczas używania struktury. Więc wszędzie w Twoim kodzie możesz napisać:

myStruct a;

Zamiast

struct myStruct a;

To oszczędza trochę pisania i może być bardziej czytelne, ale to kwestia gustu

 1
Author: shodanex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-04 17:27:34