Forskjellen mellom 'struct' og 'typedef struct' i C ++?

stemmer
686

I C ++, er det noen forskjell mellom:

struct Foo { ... };

og

typedef struct { ... } Foo;
Publisert på 04/03/2009 klokken 20:41
kilden bruker
På andre språk...                            


8 svar

stemmer
1k

I C ++, er det bare en subtil forskjell. Det er en etterlevning fra C, der det gjør en forskjell.

Den C-språk standard ( C89 §3.1.2.3 , C99 §6.2.3 , og C11 §6.2.3 ) pålegger ulike navne for forskjellige kategorier av identifikatorer, inkludert tag identifikatorer (for struct/ union/ enum) og vanlige identifikatorer (for typedefog andre identifikatorer) .

Hvis du nettopp sa:

struct Foo { ... };
Foo x;

du vil få en kompilator feil, fordi Foodet bare er definert i koden navnerom.

Du må erklære det som:

struct Foo x;

Hver gang du ønsker å referere til en Foo, vil du alltid å kalle det en struct Foo. Dette blir irriterende fort, slik at du kan legge til en typedef:

struct Foo { ... };
typedef struct Foo Foo;

struct Foo(i koden navne) og bare ren Foo(i vanlig identifikator namespace) begge refererer til det samme, og du kan fritt erklære objekter av typen Foouten structnøkkelordet.


Konstruksjonen:

typedef struct Foo { ... } Foo;

er bare en forkortelse for erklæringen og typedef.


Endelig,

typedef struct { ... } Foo;

erklærer en anonym struktur og skaper en typedeffor det. Dermed med denne konstruksjonen, det har ikke et navn i koden navnerom, bare et navn i typedef navnerom. Dette betyr at det heller ikke kan frem-erklært. Hvis du ønsker å lage en fremtids erklæring, må du gi den et navn i koden navnerom .


I C ++, alle struct/ union/ enum/ classerklæringer oppfører seg som de er implisitt typedef'ed, så lenge navnet ikke er skjult av en annen erklæring med samme navn. Se Michael Burr svar for alle detaljer.

Svarte 04/03/2009 kl. 20:45
kilden bruker

stemmer
207

I denne DDJ artikkelen , forklarer Dan Saks ett lite område der feil kan krype gjennom hvis du ikke typedef dine structs (og klasser!):

Hvis du vil, kan du forestille deg at C ++ genererer en typedef for hver kodenavn, for eksempel

typedef class string string;

Dessverre, dette er ikke helt nøyaktig. Jeg skulle ønske det var så enkelt, men det er ikke. C ++ kan ikke generere slike typedefs for structs, foreninger, eller enums uten innføring av inkompatibilitet med C.

For eksempel at en C-program erklærer både en funksjon og en struct som heter status:

int status(); struct status;

Igjen kan det være dårlig praksis, men det er C. I dette programmet, status (alene) refererer til den funksjon; struct status refererer til den type.

Hvis C ++ gjorde automatisk generere typedefs for koder, så når du kompilert programmet som C ++, vil kompilatoren generere:

typedef struct status status;

Dessverre, vil denne typen navn i strid med funksjonsnavnet, og programmet vil ikke kompilere. Det er derfor C ++ kan ikke bare generere en typedef for hver tag.

I C ++, tags fungere akkurat som typedef navn, bortsett fra at et program kan erklære et objekt, funksjon eller enumerator med samme navn og samme omfang som et merke. I dette tilfelle gjenstanden, funksjon, eller enumerator navn skjuler tagnavnet. Programmet kan referere til kodenavnet ved å bruke søkeordet klassen, struct, union, eller enum (som passer) foran kodenavn. En type navn som består av et av ordene etterfulgt av en kode er en utdypet-type-Specifier. For eksempel, struct status og enum måned er utarbeidet-type-bransjen.

Således inneholder et C-program som begge:

int status(); struct status;

oppfører seg på samme når kompilert som C ++. Navnet status alene refererer til funksjonen. Programmet kan referere til den type bare ved hjelp av utdypet-type-Specifier struct status.

Så hvordan dette lar bugs å krype inn programmer? Vurdere programmet i Listing 1 . Dette programmet definerer en klasse foo med en standard konstruktør, og en konvertering operatør som konverterer en foo objekt til char const *. Uttrykket

p = foo();

i hoved bør konstruere en foo objekt og anvende konverteringsoperatoren. Den påfølgende utgang statement

cout << p << '\n';

skal vise klasse foo, men det gjør det ikke. Det viser funksjon foo.

Dette overraskende resultat skyldes at programmet omfatter overskriften lib.h vist i Listing 2 . Denne spissen definerer en funksjon også kalt foo. Funksjonsnavnet foo skjuler klassenavn foo, slik at henvisningen til foo i hoved refererer til funksjonen, ikke klassen. Hoved kan referere til klassen bare ved anvendelse av et utdypet-type-specifier, som i

p = class foo();

Måten å unngå slik forvirring gjennom hele programmet er å legge til følgende typedef for klassenavnet foo:

typedef class foo foo;

umiddelbart før eller etter at den klassedefinisjon. Dette typedef forårsaker en konflikt mellom typenavnet foo og funksjonsnavnet foo (fra biblioteket) som vil utløse en samle-tidsfeil.

Jeg kjenner ingen som faktisk skriver disse typedefs som en selvfølge. Det krever mye disiplin. Siden forekomsten av feil som den i Listing 1 er sannsynligvis ganske små, mange du aldri kjøre på kant med dette problemet. Men hvis en feil i programvaren kan forårsake personskade, så bør du skrive typedefs uansett hvor usannsynlig feilen.

Jeg kan ikke forestille meg hvorfor noen ville ønske å skjule en klasse navn med en funksjon eller objekt navn i samme omfang som klassen. Skjule reglene i C var en feil, og de skal ikke ha blitt utvidet til klasser i C ++. Faktisk kan du rette feilen, men det krever ekstra programmering disiplin og innsats som ikke bør være nødvendig.

Svarte 04/03/2009 kl. 21:19
kilden bruker

stemmer
58

En viktig forskjell: typedefs kan ikke frem erklært. Så for typedefalternativet må du #includefilen inneholder typedef, noe som betyr alt som #includeer din .homfatter også denne filen om det direkte trenger det eller ikke, og så videre. Det kan definitivt påvirke din bygge ganger på større prosjekter.

Uten typedef, i noen tilfeller kan du bare legge frem erklæring av struct Foo;på toppen av din .hfil, og bare #includestruct definisjonen i din .cppfil.

Svarte 04/03/2009 kl. 20:54
kilden bruker

stemmer
29

Det er en forskjell, men subtil. Se på det på denne måten: struct Foointroduserer en ny type. Den andre skaper en alias kalt Foo (og ikke en ny type) for en navngitt structtype.

7.1.3 Det typedef Specifier

1 [...]

Et navn deklareres med typedef spesifiserendes blir en typedef-navn. Innenfor rammen av sin erklæring, er et typedef-navn syntaktisk ekvivalent med et nøkkelord, og navnene den type som er knyttet til identifikatoren på den måten som er beskrevet i punkt 8. typedef-navn er således et synonym for en annen type. En typedef-navn ikke innføre en ny type vei en klasse erklæring (9,1) eller enum erklæring gjør.

8 Hvis typedef erklæringen definerer en ikke navngitt klasse (eller enum), den første typedef-navn erklært av angivelsen for å være den klasse type (eller enum type) blir brukt for å betegne den klasse type (eller enum type) for koblingsformål ( 3.5). [Eksempel:

typedef struct { } *ps, S; // S is the class name for linkage purposes

Så, en typedef alltid brukes som en plassholder / synonym for en annen type.

Svarte 04/03/2009 kl. 20:49
kilden bruker

stemmer
10

Du kan ikke bruke frem erklæring med typedef struct.

Struct seg selv er en anonym type, slik at du ikke trenger en faktisk navn til å videresende olle.

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

En frem erklæring som dette wont arbeide:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types
Svarte 05/08/2013 kl. 09:18
kilden bruker

stemmer
0

En viktig forskjell mellom en 'typedef struct' og en 'struct' i C ++ er at inline-medlem initialisering i 'typedef structs' ikke vil fungere.

// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;

// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };
Svarte 11/04/2016 kl. 13:26
kilden bruker

stemmer
-1

Struct er å skape en datatype. Den typedef er å angi en kallenavn for en datatype.

Svarte 08/04/2017 kl. 03:06
kilden bruker

stemmer
-2

Det er ingen forskjell i C ++, men jeg tror på C det ville tillate deg å erklære forekomster av struct Foo uten eksplisitt gjør:

struct Foo bar;
Svarte 04/03/2009 kl. 20:44
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more