Hvorfor skal vi typedef en struct så ofte i C?

stemmer
316

Jeg har sett mange programmer som består av strukturer som det nedenfor

typedef struct 
{
    int i;
    char k;
} elem;

elem user;

Hvorfor er det nødvendig så ofte? Noen spesiell grunn eller gjeldende området?

Publisert på 31/10/2008 klokken 07:14
kilden bruker
På andre språk...                            


15 svar

stemmer
382

Som Greg Hewgill sagt, betyr typedef du ikke lenger å skrive structover alt. Som ikke bare sparer tastetrykk, det kan også gjøre koden renere fordi det gir en smidgen mer abstraksjon.

ting som

typedef struct {
  int x, y;
} Point;

Point point_new(int x, int y)
{
  Point a;
  a.x = x;
  a.y = y;
  return a;
}

blir renere når du ikke trenger å se "struct" søkeord over alt, det ser mer ut som om det virkelig er en type som heter "Point" på ditt språk. Som etter typedef, er tilfellet antar jeg.

Merk også at mens eksempel (og mine) utelatt navngi struct seg selv, faktisk navngi det er også nyttig for når du ønsker å gi en ugjennomsiktig type. Da vil du ha kode som dette i overskriften, for eksempel:

typedef struct Point Point;

Point * point_new(int x, int y);

og deretter gi structerklæring i gjennomføringen filen:

struct Point
{
  int x, y;
};

Point * point_new(int x, int y)
{
  Point *p;
  if((p = malloc(sizeof *p)) != NULL)
  {
    p->x = x;
    p->y = y;
  }
  return p;
}

I sistnevnte tilfelle, kan du ikke returnere Point i verdi, siden sin erklæring er skjult fra brukere av topptekstfilen. Dette er en teknikk som brukes i stor utstrekning i GTK + , for eksempel.

OPPDATERING Merk at det også er høyt ansett C prosjekter der denne bruken av typedefå skjule structregnes som en dårlig idé, er Linux-kjernen trolig den mest kjente slikt prosjekt. Se kapittel 5 i The Linux Kernel CodingStyle dokument for Linus' sinte ord. :) Mitt poeng er at "bør" i spørsmålet er kanskje ikke satt i stein, tross alt.

Svarte 31/10/2008 kl. 07:37
kilden bruker

stemmer
180

Det er utrolig hvor mange mennesker får denne feil. Vennligst ikke typedef structs i C, det unødvendig forurenser globale navne som vanligvis er svært forurenset allerede i store C-programmer.

Også typedef'd structs uten et kodenavn er en viktig årsak til unødvendig ileggelse av bestilling relasjoner mellom header filer.

Ta i betraktning:

#ifndef FOO_H
#define FOO_H 1

#define FOO_DEF (0xDEADBABE)

struct bar; /* forward declaration, defined in bar.h*/

struct foo {
  struct bar *bar;
};

#endif

Med en slik definisjon, ikke ved hjelp av typedefs, er det mulig for en compiland enhet for å inkludere foo.h for å få i FOO_DEFdefinisjonen. Hvis den ikke forsøker å dereference 'bar' medlem av foostruct så vil det ikke være behov for å inkludere "bar.h" filen.

Også, siden de navnerom er forskjellig mellom de kodenavn og medlemsnavnene, er det mulig å skrive svært lesbar kode som for eksempel:

struct foo *foo;

printf("foo->bar = %p", foo->bar);

Siden navnerom er separate, det er ingen konflikt i å navngi variabler sammenfallende med deres struct tag navn.

Hvis jeg har til å opprettholde koden din, vil jeg fjerne typedef'd structs.

Svarte 30/12/2010 kl. 21:20
kilden bruker

stemmer
118

Fra en gammel artikkel av Dan Saks ( http://www.ddj.com/cpp/184403396?pgno=3 ):


C-språk regler for navngiving structs er litt eksentriske, men de er ganske ufarlig. Men når utvidet til klasser i C ++, de samme regler åpne små sprekker for bugs å krype gjennom.

I C, navnet s vises i

struct s
    {
    ...
    };

er et tag. En kode navn er ikke en type navn. Gitt definisjonen ovenfor, erklæringer såsom

s x;    /* error in C */
s *p;   /* error in C */

er feil i C. Du må skrive dem som

struct s x;     /* OK */
struct s *p;    /* OK */

Navnene på fagforeninger og enumerations er også tags fremfor typer.

I C-koder er forskjellig fra alle andre navn (for funksjoner, typer, variabler, og telling konstanter). C-kompilatorer opprettholde koder i en symboltabell som er konseptuelt om ikke fysisk atskilt fra bordet som inneholder alle andre navn. Således er det mulig for en C-program for å ha både en kode og et annet navn med det samme skrivemåte i samme omfang. For eksempel,

struct s s;

er en gyldig erklæring som erklærer variable s av type struct s. Det kan ikke være god praksis, men C-kompilatorer må akseptere det. Jeg har aldri sett en begrunnelse for hvorfor C designet på denne måten. Jeg har alltid trodd det var en feil, men det er det.

Mange programmerere (inkludert undertegnede) foretrekker å tenke på struct navn som typenavn, slik at de definerer et alias for taggen ved hjelp av en typedef. For eksempel, som definerer

struct s
    {
    ...
    };
typedef struct s S;

kan du bruke S i stedet for struct s, som i

S x;
S *p;

Et program kan ikke bruke S som navnet på både en type og en variabel (eller funksjon eller oppregning konstant):

S S;    // error

Dette er bra.

Koden name i en struct, union, eller enum definisjon er valgfri. Mange programmerere fold struct definisjonen inn i typedef og dispensere med koden sammen, som i:

typedef struct
    {
    ...
    } S;

Den koblede artikkelen har også en diskusjon om hvordan C ++ oppførselen ikke requireing en typedefkan føre til subtile navnet skjuler problemer. For å forebygge disse problemene, er det en god idé å typedefklassene og structs i C ++, også, selv om ved første øyekast ser det ut til å være unødvendig. I C ++, med typedefnavnet -skjuling bli en feil som kompilatoren forteller deg om i stedet for en skjult kilde til potensielle problemer.

Svarte 31/10/2008 kl. 17:12
kilden bruker

stemmer
52

Ved hjelp av en typedefunngår å måtte skrive structhver gang du deklarerer en variabel av denne typen:

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct
Svarte 31/10/2008 kl. 07:16
kilden bruker

stemmer
35

En annen god grunn til å alltid typedef enums og structs resultater fra dette problemet:

enum EnumDef
{
  FIRST_ITEM,
  SECOND_ITEM
};

struct StructDef
{
  enum EnuumDef MyEnum;
  unsigned int MyVar;
} MyStruct;

Legg merke til skrivefeil i EnumDef i struct (Enu u mDef)? Dette kompilerer uten feil (eller advarsel) og er (avhengig av den bokstavelige tolkningen av C Standard) korrekt. Problemet er at jeg nettopp opprettet en ny (tom) oppregning definisjon innenfor mitt struct. Jeg er ikke (som forutsatt) ved hjelp av den tidligere definisjonen EnumDef.

Med en typdef lignende type skrivefeil ville ha resultert i en kompilator feil for bruk av ukjent type:

typedef 
{
  FIRST_ITEM,
  SECOND_ITEM
} EnumDef;

typedef struct
{
  EnuumDef MyEnum; /* compiler error (unknown type) */
  unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */

Jeg vil argumentere for alltid typedef'ing structs og enumerations.

Ikke bare for å spare noen typing (no pun intended;)), men fordi det er tryggere.

Svarte 31/03/2009 kl. 00:00
kilden bruker

stemmer
26

Linux-kjernen koding stil Kapittel 5 gir store fordeler og ulemper (for det meste ulemper) ved bruk typedef.

Vennligst ikke bruk ting som "vps_t".

Det er en feil å bruke typedef for strukturer og pekere. Når du ser en

vps_t a;

i kilden, hva betyr det?

I motsetning, hvis det står

struct virtual_container *a;

du kan faktisk fortelle hva "a" er.

Mange mennesker tror at typedefs "help lesbarhet". Ikke så. De er nyttige for kun:

(a) fullstendig ugjennomsiktige objekter (hvor typedef brukes aktivt for å skjule hva gjenstanden er).

Eksempel: "pte_t" osv ugjennomsiktige objekter som du kan bare få tilgang til ved å bruke de riktige aksessoregenskaper funksjoner.

MERK! Opaqueness og "aksessoregenskaper funksjoner" er ikke bra i seg selv. Grunnen til at vi har dem for ting som pte_t etc. er at det er virkelig absolutt null portably tilgjengelig informasjon der.

(b) Clear heltall typer, der abstraksjon hjelper unngå forvirring om det er "int" eller "lang".

U8 / U16 / U32 er helt greit typedefs, selv om de passer inn i kategori (d) bedre enn her.

MERK! Igjen - det må være en grunn for dette. Hvis noe er "usignert lang", så er det ingen grunn til å gjøre

typedef unsigned long myflags_t;

men hvis det er en klar begrunnelse for hvorfor det under visse omstendigheter kan være en "usignert int" og under andre konfigurasjoner kan være "usignert lang", så for all del gå videre og bruke en typedef.

(c) når du bruker sparsom til å bokstavelig talt skape en ny type for typesjekking.

(d) Nye typer som er identiske med standard C99 typer, i visse ekstreme forhold.

Selv om det bare skulle ta en kort tid for øynene og hjernen til å bli vant til standard typer som 'uint32_t', noen mennesker objekt til deres bruk uansett.

Derfor er Linux-spesifikke 'U8 / U16 / U32 / u64' typer og deres undertegnet ekvivalenter som er identiske med standardtyper tillatt - selv om de ikke er obligatorisk i ny kode til din egen.

Når du redigerer eksisterende kode som allerede bruker det ene eller det andre settet med typer, bør du være i samsvar med eksisterende valg i denne koden.

(e) Typer trygge for bruk i userspace.

I visse strukturer som er synlige for userspace, kan vi ikke kreve C99 typer, og kan ikke bruke 'U32' skjemaet ovenfor. Dermed bruker vi __u32 og lignende typer i alle strukturer som er delt med userspace.

Kanskje det er andre tilfeller også, men regelen bør i utgangspunktet være å ALDRI bruke en typedef mindre du kan tydelig matche en av disse reglene.

Generelt er en peker, eller en struct som har elementer som med rimelighet kan aksesseres direkte bør aldri være en typedef.

Svarte 07/08/2013 kl. 14:19
kilden bruker

stemmer
10

Jeg tror ikke frem erklæringer er også mulig med typedef. Bruk av struct, enum, og forening gi rom for videresending erklæringer når avhengigheter (kjenner til) er toveis.

Stil: Bruk av typedef i C ++ gjør mye fornuftig. Det kan nesten være nødvendig når du arbeider med maler som krever flere og / eller variable parametere. Den typedef bidrar til å holde navne rett.

Ikke så i C programmeringsspråk. Bruken av typedef tjener som oftest ingen hensikt enn å komplisere datastrukturen bruk. Da bare {struct (6), enum (4), union (5)} antall tastetrykk som brukes for å erklære en datatype er det nesten ikke bruk for aliasing av struct. Er det data skriver en forening eller en struct? Ved hjelp av den enkle ikke-typdefed erklæring lar deg vite med en gang hvilken type det er.

Legg merke til hvordan Linux er skrevet med strenge unngå dette aliasing tull typedef bringer. Resultatet er et minimalistisk og ren stil.

Svarte 29/05/2010 kl. 07:12
kilden bruker

stemmer
9

Det viser seg at det er fordeler og ulemper. En nyttig kilde til informasjon er den banebrytende bok "Expert C Programming" ( kapittel 3 ). Kort, i C du har flere navnerom: koder, typer, medlemsnavn og identifikatorer . typedefintroduserer et alias for en type og lokaliserer den i tag navnerommet. nemlig

typedef struct Tag{
...members...
}Type;

definerer to ting. En tag i tag navne og en type i typenamespace. Så du kan gjøre begge deler Type myTypeog struct Tag myTagType. Erklæringer som struct Type myTypeeller Tag myTagTypeer ulovlig. I tillegg, i en erklæring som dette:

typedef Type *Type_ptr;

vi definerer en peker til vår type. Så hvis vi sier:

Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;

da var1, var2og myTagType1er pekere til type, men myTagType2ikke.

I ovennevnte bok, nevner det at typedefing structs er ikke veldig nyttig som det bare sparer programmereren fra å skrive ordet struct. Men jeg har innvendinger, som mange andre C-programmerere. Selv om det noen ganger blir til obfuscate noen navn (det er derfor det ikke er tilrådelig i store kodebaser som kjernen) når du ønsker å gjennomføre polymorfisme i C det hjelper mye å se her for detaljer . Eksempel:

typedef struct MyWriter_t{
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
}MyWriter;

du kan gjøre:

void my_writer_func(MyPipe *s)
{
    MyWriter *self = (MyWriter *) s;
    uint32_t myFlags = self->flags;
...
}

Så du kan få tilgang til en ytre medlem ( flags) av den indre struct ( MyPipe) gjennom casting. For meg er det mindre forvirrende å kaste hele typen enn å gjøre (struct MyWriter_ *) s;hver gang du ønsker å utføre en slik funksjonalitet. I disse tilfellene kort referering er en stor avtale, spesielt hvis du tungt benytter teknikken i koden.

Til slutt, den siste aspektet med typedefed typer er manglende evne til å utvide dem, i motsetning til makroer. Hvis du for eksempel har du:

#define X char[10] or
typedef char Y[10]

du kan deretter erklære

unsigned X x; but not
unsigned Y y;

Vi har egentlig ikke bryr seg om dette for structs fordi den ikke gjelder lagringsbransjen ( volatileog const).

Svarte 11/08/2013 kl. 15:48
kilden bruker

stemmer
3

La oss starte med det grunnleggende og jobbe oss oppover.

Her er et eksempel på struktur definisjon:

struct point
  {
    int x, y;
  };

Her navnet pointer valgfritt.

En konstruksjon kan bli erklært i løpet av dens definisjon, eller etter.

Å erklære under definisjonen

struct point
  {
    int x, y;
  } first_point, second_point;

Å erklære etter definisjon

struct point
  {
    int x, y;
  };
struct point first_point, second_point;

Nå oppmerksom nøye den siste saken ovenfor; du trenger å skrive struct pointfor å erklære Strukturer av denne typen hvis du bestemmer deg for å lage denne typen på et senere tidspunkt i koden din.

Enter typedef. Hvis du har tenkt å lage ny struktur (Struktur er en tilpasset data-type) på et senere tidspunkt i programmet med samme blåkopi, ved hjelp typedefunder definisjonen kan være en god idé, siden du kan spare skrive fremover.

typedef struct point
  {
    int x, y;
  } Points;

Points first_point, second_point;

Et ord av forsiktighet mens navngi tilpasset type

Ingenting hindrer deg fra å bruke _t suffiks på slutten av tilpasset type men POSIX standarden forbeholder seg bruk av suffikset _t å betegne standard bibliotek typenavn.

Svarte 09/03/2018 kl. 18:16
kilden bruker

stemmer
3

navnet du (eventuelt) gi struct kalles kodenavn , og som har vært nevnt, er ikke en type i seg selv. For å komme til den typen krever struct prefiks.

GTK + til side, jeg er ikke sikker på tagname brukes noe sånt som vanlig som en typedef til struct typen, så i C ++ som er anerkjent, og du kan utelate struct søkeord og bruke tagname som type navn også:


    struct MyStruct
    {
      int i;
    };

    // The following is legal in C++:
    MyStruct obj;
    obj.i = 7;

Svarte 31/10/2008 kl. 08:24
kilden bruker

stemmer
1

A> a typdef hjelpemidler i betydningen og dokumentasjon av et program ved å tillate etablering av mer meningsfulle synonymer for datatyper . I tillegg hjelper de parametrisere et program mot bærbarhet problemer (K & R, pg147, C prog lang).

B> en struktur som definerer en type . Structs gir praktisk gruppering av en samling av vars for praktisk håndtering (K & R, pg127, C prog lang.) Som en enkelt enhet

C> typedef'ing et struct er forklart i A ovenfor.

D> For meg structs er tilpassede typer eller beholdere eller samlinger eller navnerom eller komplekse typer, mens en typdef er bare et middel for å skape flere kallenavn.

Svarte 05/07/2017 kl. 00:19
kilden bruker

stemmer
1

typedef vil ikke gi en co-avhengige sett av datastrukturer. Dette kan du ikke gjøre med typdef:

struct bar;
struct foo;

struct foo {
    struct bar *b;
};

struct bar {
    struct foo *f;
};

Selvfølgelig kan du alltid legge til:

typedef struct foo foo_t;
typedef struct bar bar_t;

Hva er egentlig poenget med det?

Svarte 30/01/2016 kl. 15:47
kilden bruker

stemmer
0

Det viser seg i C99 typedef er nødvendig. Det er utdatert, men mye av verktøy (ala HackRank) bruke C99 som sin rene C gjennomføring. Og typedef kreves der.

Jeg sier ikke at de skal endre (har kanskje to C opsjoner) dersom kravet endret, de av oss studere for intervjuer på området ville være SOL.

Svarte 02/11/2016 kl. 09:34
kilden bruker

stemmer
0

I 'C' programmeringsspråk søkeordet 'typedef' brukes for å erklære et nytt navn for noen objekt (struct, array, function..enum type). For eksempel vil jeg bruke en struct-s '. I 'C' vi erklærer ofte en struct 'utenfor '' hovedfunksjon. For eksempel:

struct complex{ int real_part, img_part }COMPLEX;

main(){

 struct KOMPLEKS number; // number type is now a struct type
 number.real_part = 3;
 number.img_part = -1;
 printf("Number: %d.%d i \n",number.real_part, number.img_part);

}

Hver gang jeg velger å bruke en struct type I vil trenge dette søkeordet 'struct 'noe' 'navn'.' Typedef' vil bare endre navn på denne typen, og jeg kan bruke det nye navnet på programmet mitt hver gang jeg vil. Så vår kode vil være:

typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.

main(){

COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);

}

Hvis du har noen lokal objekt (struct, array, verdifull) som vil bli brukt i hele programmet kan du bare gi den et navn ved hjelp av en 'typedef'.

Svarte 11/06/2016 kl. 00:50
kilden bruker

stemmer
-1

I det hele tatt, i C-språk, struct / forening / enum er makro instruksjon behandles av C-språk preprosessor (ikke forveksle med preprosessor som behandler "# include" og andre)

så:

struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};

struct b er brukt som noe sånt som dette:

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}

og så, under kompiler det utvikle seg på stabelen som omtrent slik: b: int ai int i int j

som også hvorfor det er dificult å ha selfreferent structs, C preprosessor rundt i en erklæring løkke som ikke kan avslutte.

typedef er typebeskrivelse, det betyr bare C-kompilator prosess det og det kan gjøre som han vil bruke for å optimalisere assembler-kode gjennomføring. Det er også ikke expend medlem av type par dumt som preprosessor gjøre med structs men bruker mer kompleks referansen konstruksjon algoritmen, slik konstruksjon som:

typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;

er permited og funksjonell. Denne implementeringen gir også tilgang til kompilator Typekonversjon og fjerne noen bugging effekter når utførelsen tråden forlater anvendelsesområdet for initialisering funksjoner.

Dette betyr at i C typedefs er mer nær som C ++ klasse enn ensomme structs.

Svarte 06/03/2010 kl. 14:54
kilden bruker

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