typedef struct vs struct definities

Ik ben een beginner in C-programmeren, maar ik vroeg me af wat het verschil is tussen het gebruik van typedefbij het definiëren van een structuur en het niet gebruiken van typedef. Het lijkt mij alsof er echt geen verschil is, ze bereiken hetzelfde doel.

struct myStruct{
    int one;
    int two;
};

vs.

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

Antwoord 1, autoriteit 100%

Het gemeenschappelijke idioom gebruikt beide:

typedef struct S { 
    int x; 
} S;

Het zijn verschillende definities. Om de discussie duidelijker te maken zal ik de zin splitsen:

struct S { 
    int x; 
};
typedef struct S S;

In de eerste regel definieert u de identifier Sbinnen de structuurnaamruimte (niet in de C++-zin). U kunt het gebruiken en variabelen of functieargumenten van het nieuw gedefinieerde type definiëren door het type van het argument te definiëren als struct S:

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

De tweede regel voegt een type alias Stoe aan de globale naamruimte en stelt je dus in staat om gewoon te schrijven:

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

Merk op dat aangezien beide id-naamruimten verschillend zijn, het definiëren van Szowel in de structs als in de globale spaties geen fout is, omdat het niet dezelfde identifier opnieuw definieert, maar eerder een andere identifier maakt in een andere plaats.

Om het verschil duidelijker te maken:

typedef struct S { 
    int x; 
} T;
void S() { } // correct
//void T() {} // error: symbol T already defined as an alias to 'struct S'

Je kunt een functie definiëren met dezelfde naam als de struct omdat de identifiers in verschillende ruimtes worden bewaard, maar je kunt geen functie definiëren met dezelfde naam als een typedefomdat die identifiers botsen.

In C++ is het iets anders omdat de regels om een symbool te lokaliseren subtiel zijn veranderd. C++ behoudt nog steeds de twee verschillende identificatieruimten, maar in tegenstelling tot C, wanneer u alleen het symbool definieert binnen de klasse-identificatieruimte, bent u niet verplicht om het sleutelwoord struct/class op te geven:

// C++
struct S { 
    int x; 
}; // S defined as a class
void f( S a ); // correct: struct is optional

Welke wijzigingen zijn de zoekregels, niet waar de identifiers zijn gedefinieerd. De compiler doorzoekt de globale identifier-tabel en nadat Sniet is gevonden, zoekt hij naar Sbinnen de class-identifiers.

De eerder gepresenteerde code gedraagt zich op dezelfde manier:

typedef struct S { 
    int x; 
} T;
void S() {} // correct [*]
//void T() {} // error: symbol T already defined as an alias to 'struct S'

Na de definitie van de functie Sin de tweede regel, kan de struct Sniet automatisch worden opgelost door de compiler, en om een object te maken of een argument van op dat type moet u terugvallen om het trefwoord structop te nemen:

// previous code here...
int main() {
    S(); 
    struct S s;
}

Antwoord 2, autoriteit 14%

structen typedefzijn twee heel verschillende dingen.

Het sleutelwoord structwordt gebruikt om een structuurtype te definiëren of ernaar te verwijzen. Bijvoorbeeld dit:

struct foo {
    int n;
};

maakt een nieuw type met de naam struct foo. De naam foois een tag; het heeft alleen betekenis als het onmiddellijk wordt voorafgegaan door het sleutelwoord struct, omdat tags en andere ID’s in verschillende naamruimtenstaan. (Dit is vergelijkbaar met, maar veel beperkter dan, het C++-concept van namespaces.)

Een typedefdefinieert, ondanks de naam, geen nieuw type; het creëert slechts een nieuwe naam voor een bestaand type. Bijvoorbeeld, gegeven:

typedef int my_int;

my_intis een nieuwe naam voor int; my_inten intzijn exactvan hetzelfde type. Op dezelfde manier kun je, gezien de struct-definitie hierboven, schrijven:

typedef struct foo foo;

Het type heeft al een naam, struct foo. De typedef-declaratie geeft hetzelfde type een nieuwe naam, foo.

Met de syntaxis kun je een structen typedefcombineren in een enkele declaratie:

typedef struct bar {
    int n;
} bar;

Dit is een veelvoorkomend idioom. Nu kunt u naar dit structuurtype verwijzen als struct barof gewoon als bar.

Houd er rekening mee dat de typedef-naam pas aan het einde van de aangifte zichtbaar wordt. Als de structuur een verwijzing naar zichzelf bevat, moet u de versie structgebruiken om ernaar te verwijzen:

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

Sommige programmeurs gebruiken verschillende identifiers voor de struct-tag en voor de typedef-naam. Naar mijn mening is daar geen goede reden voor; het gebruik van dezelfde naam is volkomen legaal en maakt het duidelijker dat ze van hetzelfde type zijn. Als u verschillende identifiers moet gebruiken, gebruik dan in ieder geval een consistente conventie:

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

(Persoonlijk geef ik er de voorkeur aan om de typedefweg te laten en naar het type te verwijzen als struct bar. De typedefbespaart een beetje typen, maar het verbergt het feit dat het een structuurtype is. Als u wilt dat het type ondoorzichtig is, kan dit een goede zaak zijn. Als de klantcode gaat verwijzen naar het lid nbij naam, dan is het niet ondoorzichtig; het is zichtbaar een structuur, en naar mijn mening is het logisch om er naar te verwijzen als een structuur. Maar veel slimme programmeurs zijn het op dit punt niet met me eens. Wees bereid om de code die hoe dan ook is geschreven te lezen en te begrijpen.)

(C++ heeft verschillende regels. Gezien een verklaring van struct blah, kunt u verwijzen naar het type als alleen blah, zelfs zonder typedef. Het gebruik van een typedef kan maken Uw C-code Een beetje meer C++ – zoals – als u denkt dat dit een goede zaak is.)


3, Autoriteit 8%

Een ander verschil dat niet opmerkt, is dat het geven van de struct een naam (d.w.z. struct-mystruct) u ook in staat stelt u ook voorwaartse verklaringen van de struct te bieden. Dus in een ander bestand, zou je kunnen schrijven:

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

zonder toegang te hebben tot de definitie. Wat ik aanrader, kun je je twee voorbeelden combineren:

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

Hiermee kunt u het gemak van de meer beknopte typedefnaam, maar stelt u nog steeds in staat om de volledige struct-naam te gebruiken als u nodig hebt.


4, Autoriteit 3%

Als u structzonder typedefgebruikt, moet u altijd

schrijven

struct mystruct myvar;

Het is illegaal om

te schrijven

mystruct myvar;

Als u de typedefgebruikt, hebt u de structvoorvoegsel niet meer nodig.


5, Autoriteit 2%

In C, het type Dubbelfunctionele trefwoorden van structuren, vakbonden en instructies zijn verplicht, dwz u altijd de naam van het type (de naam ) moet voorvoegen met struct, unionof enumbij het verwijzen naar het type.

U kunt de zoekwoorden verwijderen met behulp van een typedef, hetgeen een vorm is van informatie die zich verstopt, omdat het eigenlijke type van een object niet langer zichtbaar zal zijn bij het declareren.

Het wordt daarom aanbevolen (zie bijvoorbeeld de Linux kernel coderingstijl gids , hoofdstuk 5) om dit alleen te doen wanneer
U wilt eigenlijk Wilt u om deze informatie te verbergen en niet alleen om een ​​paar toetsaanslagen op te slaan.

Een voorbeeld van wanneer u een typedefzou moeten gebruiken, zou een ondoorzichtig type zijn dat alleen wordt gebruikt met bijbehorende accessorfuncties / macro’s.


6

De volgende code creëert een anonieme struct met de alias myStruct:

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

U kunt het niet verwijzen zonder de alias omdat u geen identificatie voor de structuur opgeeft.


7

U kunt geen voordelige verklaring gebruiken met de typedef struct.

De structzelf is een anoniem type, dus u hebt geen echte naam om door te duiden.

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

Een voordelige verklaring zoals deze werkt niet:

struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types

8

Het verschil komt binnen wanneer u de structgebruikt.

De eerste manier die u moet doen:

struct myStruct aName;

Op de tweede manier kunt u het zoekwoord verwijderen struct.

myStruct aName;

9

De typedef, zoals het is met andere constructen, wordt gebruikt om een ​​gegevenstype een nieuwe naam te geven. In dit geval wordt het meestal gedaan om de code-reiniger te maken:

struct myStruct blah;

vs.

myStruct blah;

10

Ik zie dat sommige verduidelijking hierop is. C en C++ definiëren typen niet anders. C++ was oorspronkelijk niets meer dan een extra set van omvat bovenop c.

Het probleem dat vrijwel alle C / C++ ontwikkelaars vandaag hebben, is a) universiteiten zijn niet langer de fundamentals en b) mensen die het verschil tussen een definitie en een verklaring niet begrijpen.

De enige reden waarom dergelijke verklaringen en definities bestaan, is dat de linker adresverschuivingen naar de velden in de structuur kan berekenen. Dit is de reden waarom de meeste mensen wegkomen met code die eigenlijk verkeerd is geschreven – omdat de compiler de adressering kan bepalen. Het probleem doet zich voor wanneer iemand iets vooruit probeert te doen, zoals een wachtrij of een gelinkte lijst, of meeliften op een O/S-structuur.

Een declaratie begint met ‘struct’, een definitie begint met ‘typedef’.

Verder heeft een struct een voorwaarts declaratielabel en een gedefinieerd label. De meeste mensen weten dit niet en gebruiken het voorwaartse declaratielabel als een definitielabel.

Fout:

struct myStruct
   {
   int field_1;
   ...
   };

Ze hebben zojuist de forward-declaratie gebruikt om de structuur te labelen – dus nu weet de compiler het – maar het is geen echt gedefinieerd type. De compiler kan de adressering berekenen, maar dit is niet hoe het bedoeld was om te gebruiken, om redenen die ik zo dadelijk zal laten zien.

Mensen die deze vorm van declaratie gebruiken, moeten altijd ‘struct’ in praktisch elke verwijzing ernaar plaatsen — omdat het geen officieel nieuw type is.

In plaats daarvan moet elke structuur die niet naar zichzelf verwijst, alleen op deze manier worden gedeclareerd en gedefinieerd:

typedef struct
   {
   field_1;
   ...
   }myStruct;

Nu is het een echt type, en als je het gebruikt, kun je at gebruiken als ‘myStruct’ zonder het woord ‘struct’ eraan vooraf te laten gaan.

Als je een pointervariabele naar die structuur wilt, voeg dan een secundair label toe:

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

Nu heb je een aanwijzer variabel op die structuur, gewoon eraan.

Verklaring van Forward –

Nu, hier is het mooie spul, hoe de voorwaartse verklaring werkt. Als u een type wilt maken dat naar zichzelf verwijst, zoals een gekoppelde lijst of wachtrij-element, moet u een voorwaartse verklaring gebruiken. De compiler beschouwt niet de structuur die is gedefinieerd totdat deze aan het einde aan de puntkomma’s komt, dus het wordt net vóór die punt aangegeven.

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

Nu, de compiler weet dat hoewel het niet weet wat het hele type nog is, het nog steeds kan verwijzen met behulp van de voorwaartse referentie.

Verklaar en typedef uw structuren correct. Er is eigenlijk een reden.


11

Met het laatste voorbeeld laat u het struct-trefwoord weglaten bij gebruik van de structuur. Dus overal in uw code kunt u schrijven:

myStruct a;

in plaats van

struct myStruct a;

Dit bespaart wat typen en kan meer leesbaar zijn, maar dit is een kwestie van smaak

Other episodes