Waarom zouden we zo vaak in c typdef hebben in C?

Ik heb veel programma’s gezien die bestaan ​​uit structuren zoals de onderstaande

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

Waarom is het zo vaak nodig? Een specifieke reden of toepasselijk gebied?


1, Autoriteit 100%

Zoals Greg Hewgill zei, betekent het typedeof dat u niet langer structoveral hoeft te schrijven. Dat bespaart niet alleen toetsaanslagen, het kan ook de codecleaner maken, omdat het een mogen meer abstractie biedt.

dingen zoals

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

wordt schoner wanneer u het “struct” -woord niet overal hoeft te zien, het ziet er meer uit alsof er echt een type “punt” in uw taal is. Welke, na de typedef, is het geval dat ik denk.

Houd er ook rekening mee dat terwijl uw voorbeeld (en de mijne) de naam van de structzelf namen, eigenlijk het noemen, het is ook handig voor wanneer u een ondoorzichtig type wilt bieden. Dan zou je als volgt in de kop code hebben, bijvoorbeeld:

typedef struct Point Point;
Point * point_new(int x, int y);

en verstrek vervolgens de structdefinitie in het implementatiebestand:

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

In dit laatste geval kunt u de Point by-waarde niet retourneren, omdat de definitie ervan verborgen is voor gebruikers van het headerbestand. Dit is een techniek die veel wordt gebruikt in bijvoorbeeld GTK+.

UPDATEMerk op dat er ook hoog aangeschreven C-projecten zijn waar dit gebruik van typedefom structte verbergen als een slecht idee wordt beschouwd, de Linux-kernel is waarschijnlijk het meest bekende project. Zie hoofdstuk 5 van Het Linux Kernel CodingStyle-documentvoor de boze woorden van Linus. 🙂 Mijn punt is dat het “zou moeten” in de vraag misschien toch niet in steen gebeiteld is.


Antwoord 2, autoriteit 45%

Het is verbazingwekkend hoeveel mensen dit verkeerd begrijpen. GELIEVE geen structs in C te typen, het vervuilt nodeloos de globale naamruimte die typisch al erg vervuild is in grote C-programma’s.

Ook getypte structs zonder tagnaam zijn een belangrijke oorzaak van het onnodig opleggen van ordeningsrelaties tussen headerbestanden.

Overweeg:

#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

Met een dergelijke definitie, zonder gebruik te maken van typedefs, is het voor een compiland-eenheid mogelijk om foo.h op te nemen om bij de FOO_DEF-definitie te komen. Als het niet probeert het ‘bar’-lid van de foo-struct te dereferentie, is het niet nodig om het bestand “bar.h” op te nemen.

Omdat de naamruimten tussen de tagnamen en de ledennamen verschillen, is het ook mogelijk om zeer leesbare code te schrijven, zoals:

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

Omdat de naamruimten gescheiden zijn, is er geen conflict bij het benoemen van variabelen die samenvallen met hun struct-tagnaam.

Als ik je code moet onderhouden, zal ik je getypte structs verwijderen.


Antwoord 3, autoriteit 29%

Uit een oud artikel van Dan Saks (http://www.ddj.com/ cpp/184403396?pgno=3):


De C-taalregels voor naamgeving
structuren zijn een beetje excentriek, maar
ze zijn vrij ongevaarlijk. Echter, wanneer?
uitgebreid tot klassen in C++, diezelfde
regels openen kleine scheurtjes voor bugs om
doorkruipen.

In C verschijnt de naam in

struct s
    {
    ...
    };

is een tag. Een tagnaam is geen type
naam. Gezien de bovenstaande definitie,
verklaringen zoals

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

zijn fouten in C. Je moet ze schrijven
als

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

De namen van vakbonden en opsommingen
zijn ook tags in plaats van typen.

In C onderscheiden tags zich van alle andere
namen (voor functies, typen,
variabelen en opsommingsconstanten).
C-compilers onderhouden tags in een symbool
tafel dat is conceptueel zo niet
fysiek gescheiden van de tafel
die alle andere namen bevat. Dus het is
is het mogelijk dat een C-programma
zowel een tag als een andere naam met
dezelfde spelling in hetzelfde bereik.
Bijvoorbeeld,

struct s s;

is een geldige verklaring die verklaart
variabele s van het type struct s. Het kan
geen goede gewoonte zijn, maar C-compilers
moet het accepteren. ik heb nog nooit een gezien
reden waarom C dit is ontworpen
manier. Ik heb altijd gedacht dat het een
fout, maar daar is het.

Veel programmeurs (inclusief die van jou)
echt) denk liever aan structnamen
als typenamen, dus ze definiëren een alias
voor de tag met behulp van een typedef. Voor
voorbeeld, definiëren

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

laat je S gebruiken in plaats van struct s,
zoals in

S x;
S *p;

Een programma kan S niet gebruiken als de naam van
zowel een type als een variabele (of
functie of opsommingsconstante):

S S;    // error

Dit is goed.

De tagnaam in een struct, union of
enum-definitie is optioneel. Veel
programmeurs vouwen de structuurdefinitie
in de typedef en laat de . achterwege
tag helemaal, zoals in:

typedef struct
    {
    ...
    } S;

Het gelinkte artikel bevat ook een discussie over hoe het C++-gedrag van het niet vereisen van een typedefsubtiele naamverbergingsproblemen kan veroorzaken. Om deze problemen te voorkomen, is het een goed idee om je klassen en structs ook in C++ te typedef, ook al lijkt dit op het eerste gezicht niet nodig. In C++ wordt met de typedefhet verbergen van de naam een fout waarover de compiler je vertelt in plaats van een verborgen bron van potentiële problemen.


Antwoord 4, autoriteit 13%

Het gebruik van een typedefvoorkomt dat u elke keer dat u een variabele van dat type declareert structmoet schrijven:

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct

Antwoord 5, autoriteit 9%

Nog een goede reden om altijd enums en structs te typen, komt voort uit dit probleem:

enum EnumDef
{
  FIRST_ITEM,
  SECOND_ITEM
};
struct StructDef
{
  enum EnuumDef MyEnum;
  unsigned int MyVar;
} MyStruct;

Zie je de typfout in EnumDef in de struct (EnuumDef)? Deze compileert foutloos (of waarschuwing) en is (afhankelijk van de letterlijke interpretatie van de C Standard) correct. Het probleem is dat ik zojuist een nieuwe (lege) opsommingsdefinitie binnen mijn structuur heb gemaakt. Ik gebruik niet (zoals bedoeld) de vorige definitie EnumDef.

Met een typdef zouden soortgelijke typefouten hebben geresulteerd in compilerfouten voor het gebruik van een onbekend 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) */

Ik zou pleiten voor ALTIJD het typen van structuren en opsommingen.

Niet alleen om wat typen te besparen (geen woordspeling bedoeld ;)), maar omdat het veiliger is.


6, Autoriteit 3%

Ik denk niet dat de aangiften zelfs mogelijk zijn met typedef. Gebruik van Struct, Enum en Unie zorgen voor doorsturen van aangiften wanneer afhankelijkheden (weet) bidirectioneel is.

Stijl:
Het gebruik van typedef in C++ maakt nogal wat zin. Het kan bijna nodig zijn bij het omgaan met sjablonen die meerdere en / of variabele parameters vereisen. De typedef helpt de naamgeving recht te houden.

Niet zo in de C-programmeertaal. Het gebruik van typedef dient meestal geen doel, maar om het gebruik van de gegevensstructuur te versmelten. Omdat alleen {struct (6), ENUM (4), Union (5)} Aantal toetsaanslagen wordt gebruikt om een ​​gegevenstype te declareren, is er bijna geen gebruik voor de aliasing van de struct. Is dat gegevenstype een unie of een structuur? Met behulp van de rechtlijnige niet-typdefed-aangifte kunt u meteen weten welk type het is.

Merk op hoe Linux is geschreven met een strikte vermijding van deze aliasing-nonsense typedef brengt. Het resultaat is een minimalistische en schone stijl.


7

Laten we beginnen met de basis en werk onze weg naar boven.

Hier is een voorbeeld van structuurdefinitie:

struct point
  {
    int x, y;
  };

Hier de naam pointis optioneel.

Een structuur kan tijdens de definitie of daarna worden gedeclareerd.

DOESTELLINGEN TIJDENS DESFINITIE

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

Verwijderen na definitie

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

Noteer nu voorzichtig het laatste geval hierboven; U moet struct pointschrijven om structuren van dat type te declareren als u besluit dat type op een later punt in uw code te maken.

Voer typedefin. Als u van plan bent om nieuwe structuur te creëren (structuur is een aangepast gegevenstype) op een later tijdstip in uw programma met dezelfde blauwdruk, met behulp van typedeftijdens de definitie kan een goed idee zijn, omdat u wat kunt besparen typen verplaatsen vooruit.

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

een woord van de voorzichtigheid bij het benoemen van uw aangepaste type

Niets voorkomt dat u _t-achtervoegsel gebruikt aan het einde van uw aangepaste typenaam, maar Posix-standaard behoudt zich het gebruik van achtervoegsel _t voor om standaard-bibliotheektype-namen aan te duiden.


8

De naam die u (optioneel) geeft, de struct wordt de naam -tagnaam genoemd en, zoals opgemerkt, is geen type op zichzelf. Om naar het type te gaan, vereist het struct-prefix.

GTK + opzij, ik weet niet zeker of de tagname zoiets als gewoonlijk als typedef wordt gebruikt voor het struct-type, dus in C++ die wordt erkend en u kunt het struct-trefwoord weglaten en de tagnaam gebruiken als de naam van het type:


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


9

Typedef biedt geen mede-afhankelijke set datastructuren. Dit kan niet met typdef doen:

struct bar;
struct foo;
struct foo {
    struct bar *b;
};
struct bar {
    struct foo *f;
};

Natuurlijk kunt u altijd toevoegen:

typedef struct foo foo_t;
typedef struct bar bar_t;

Wat is precies het punt van dat?


10

A & GT;
Een typdef helpt bij de betekenis en documentatie van een programma door creatie van meer betekenisvolle synoniemen voor gegevenstypen toe te staan. Bovendien helpen ze het parametreren van een programma tegen draagbaarheidsproblemen (K & AMP; R, PG147, C PROG LANG).

B & GT;
Een structuur definieert een type . Studenten kunnen handige groepering van een verzameling VAR’s voor het gemak van het hanteren (K & AMP; R, PG127, C PROG LANG.) Als een enkele eenheid

C & GT;
typedef’ing Een structuur wordt in een bovenstaande uitgelegd.

D & GT; Voor mij zijn structuren aangepaste typen of containers of collecties of naamruimten of complexe typen, terwijl een typdef slechts een middel is om meer bijnamen te creëren.


11

Blijkbaar in C99 is typedef vereist. Het is verouderd, maar veel tools (ala HackRank) gebruiken c99 als pure C-implementatie. En typedef is daar vereist.

Ik zeg niet dat ze zouden moeten veranderen (misschien hebben ze twee C-opties) als de vereiste zou veranderen, zouden degenen onder ons die studeren voor interviews op de site SOL zijn.


Antwoord 12

In de programmeertaal ‘C’ wordt het sleutelwoord ‘typedef’ gebruikt om een nieuwe naam voor een object (struct, array, function..enum type) te declareren. Ik zal bijvoorbeeld een ‘struct-s’ gebruiken.
In ‘C’ declareren we vaak een ‘struct’ buiten de ‘main’ functie. Bijvoorbeeld:

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

Elke keer als ik besluit een struct-type te gebruiken, heb ik dit trefwoord ‘struct ‘something’ ‘name’ nodig.’typedef’ zal dat type gewoon hernoemen en ik kan die nieuwe naam in mijn programma gebruiken wanneer ik maar wil. Onze code is dus:

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

Als je een lokaal object (struct, array, waardevol) hebt dat in je hele programma zal worden gebruikt, kun je het eenvoudig een naam geven met een ‘typedef’.


Antwoord 13

In de C-taal zijn struct/union/enum macro-instructies die worden verwerkt door de preprocessor van de C-taal (vergis u niet met de preprocessor die “#include” en andere behandelt)

dus :

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

struct b wordt als volgt uitgegeven:

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

en dus, tijdens het compileren, evolueert het op de stapel als iets als:
B:
int ai
int i
int j

daarom is het ook moeilijk om naar zichzelf verwijzende structs, C-preprocessorrondes in een declaratielus te hebben die niet kan worden beëindigd.

typedef zijn typespecificaties, wat betekent dat alleen de C-compiler het kan verwerken en het kan doen wat hij wil voor het optimaliseren van de assembler-code-implementatie. Het besteedt ook geen lid van het type par dom zoals préprocessor doet met structs, maar gebruikt een meer complex referentieconstructie-algoritme, dus constructie zoals:

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

is toegestaan en volledig functioneel. Deze implementatie geeft ook toegang tot de conversie van het compilertype en verwijdert enkele bug-effecten wanneer de uitvoeringsthread het toepassingsveld van initialisatiefuncties verlaat.

Dit betekent dat in C typedefs meer in de buurt komen van de C++-klasse dan van eenzame structs.

Other episodes