Warum verwenden Sie typedef, wenn Sie eine Aufzählung in C ++ deklarieren?

183

Ich habe seit Jahren kein C ++ mehr geschrieben und jetzt versuche ich, mich wieder darauf einzulassen. Ich bin dann darauf gestoßen und habe darüber nachgedacht aufzugeben:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Was ist das? Warum ist dertypedef Schlüsselwort verwendet? Warum kommt der Name TokenTypein dieser Erklärung zweimal vor? Wie unterscheidet sich die Semantik davon:

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};
Tim Merrifield
quelle

Antworten:

156

Wenn Sie in C Ihre Aufzählung auf die erste Weise deklarieren, können Sie sie folgendermaßen verwenden:

TokenType my_type;

Wenn Sie den zweiten Stil verwenden, müssen Sie Ihre Variable folgendermaßen deklarieren:

enum TokenType my_type;

Wie von anderen erwähnt, macht dies in C ++ keinen Unterschied. Ich vermute, dass entweder die Person, die dies geschrieben hat, im Herzen ein C-Programmierer ist oder Sie C-Code als C ++ kompilieren. In beiden Fällen wird das Verhalten Ihres Codes nicht beeinflusst.

Ryan Fox
quelle
12
Ihre Frage ist nur für C richtig, nicht aber für C ++. In C ++ können Enums und Strukturen direkt verwendet werden, als ob es ein typedef gäbe.
David Rodríguez - Dribeas
7
Nun ja, aber dies beantwortet die eigentliche Frage, die gestellt wurde und die sich wirklich mit "Was bedeutet das überhaupt?" Befasste.
BobbyShaftoe
Ist das also technisch ein Typedef oder eine Aufzählung?
Miek
5
Es ist beides. Sie könnten auch sagen: enum TokenType_ {...}; typedef enum TokenType_ TokenType;
Ryan Fox
Die Antwort ist vollständig, aber ich glaube, der Punkt ist, dass der TokenType; Nach der Enum-Deklaration wird der Typname deklariert. Die Antwort ist also nicht zu 100% vollständig. Wenn Sie "den ersten Weg" deklarieren, werden BEIDE eine Aufzählung und ein neuer Typname angegeben, der diese Aufzählung in einem Syntaxblock darstellt. Die Antwort war also hilfreich, aber ich denke, sie könnte ein bisschen verbessert werden. Vielleicht war ich zu hart, um abzustimmen. Also habe ich es nach all dem positiv bewertet. Wenn ich mir wirklich sicher wäre, würde ich die Antwort bearbeiten / verbessern ... aber das ist eine ziemlich gute Antwort
Ross Youngblood
97

Es ist ein C-Erbe in C, wenn Sie Folgendes tun:

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

Sie müssen es verwenden, um Folgendes zu tun:

enum TokenType foo;

Aber wenn Sie dies tun:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Sie können Folgendes deklarieren:

TokenType foo;

In C ++ können Sie jedoch nur die vorherige Definition verwenden und sie wie in einem C-Typedef verwenden.

Matte
quelle
1
Was Sie sagen, ist in C wahr. Es ist nicht wahr in C ++.
Jonathan Leffler
49
Ist das nicht das, was ich in meinem letzten Satz gesagt habe?
Matte
2
@mat Ich habe Ihren Kommentar zum letzten Satz positiv bewertet, aber um fair zu sein, ist er schlecht formuliert und verwirrend.
AR
20

Sie müssen es nicht tun. In C (nicht C ++) mussten Sie enum Enumname verwenden , um auf ein Datenelement vom Aufzählungstyp zu verweisen. Um es zu vereinfachen, durften Sie es in einen einzelnen Namensdatentyp eingeben .

typedef enum MyEnum { 
  //...
} MyEnum;

erlaubte, dass Funktionen, die einen Parameter der Aufzählung nehmen, definiert werden als

void f( MyEnum x )

statt der längeren

void f( enum MyEnum x )

Beachten Sie, dass der Name des Typnamens nicht mit dem Namen der Aufzählung übereinstimmen muss. Das gleiche passiert mit Strukturen.

In C ++ ist dies jedoch nicht erforderlich, da Aufzählungen, Klassen und Strukturen direkt als Typen über ihre Namen aufgerufen werden können.

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C
David Rodríguez - Dribeas
quelle
Eigentlich denke ich, dass dies eine bessere Antwort sein kann als die allgemein akzeptierte, da es klar erklärt, warum es anders ist.
Ross Youngblood
11

In C ist es ein guter Stil, da Sie den Typ in etwas anderes als eine Aufzählung ändern können.

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

In C ++ können Sie die Aufzählung so definieren, dass sie als C ++ oder C kompiliert wird.

Sei gewarnt
quelle
Willst du nicht sagen In C++ you can *typedef* the enum so that it will compile as C++ or C.? Sie sagten: In C++ you can define the enum so that it will compile as C++ or C.Beachten Sie, wie ich Ihre geändert definehabe typedef. Nun ... Ich nehme typedefing ist zu definieren.
Gabriel Staples
6

Holdover von C.

Tim
quelle
Keine Ahnung, dass das "frühe" Qualifikationsspiel relevant ist; Sie würden das immer noch in C schreiben, wenn Sie den Typnamen ohne das Präfix enum verwenden möchten.
Jonathan Leffler
1
wahr. Ich werde es löschen. Ich habe die C-Spezifikation lange nicht mehr befolgt. Ich war zu faul, um die c / c ++ - Unterscheidung zu überprüfen ... -1 für mich.
Tim
6

Einige Leute sagen, C habe keine Namespaces, aber das ist technisch nicht korrekt. Es hat drei:

  1. Schlagworte ( enum, union, und struct)
  2. Etiketten
  3. (alles andere)

typedef enum { } XYZ;deklariert eine anonyme Aufzählung und importiert sie mit dem Namen in den globalen Namespace XYZ.

typedef enum ABC { } XYZ;deklariert eine ABCim Tag-Namespace benannte Aufzählung und importiert sie dann als in den globalen Namespace XYZ.

Einige Leute möchten sich nicht mit den separaten Namespaces beschäftigen, also tippen sie alles ein. Andere tippen nie, weil sie den Namespace wollen.

russbishop
quelle
Das ist nicht genau richtig. Strukturen, Gewerkschaften und Aufzählungen werden durch den Tag-Namen referenziert (sofern nicht anonym, wie Sie erwähnt haben). Es gibt separate Namespaces für Typen und Tags. Sie können einen Typ mit genau demselben Namen wie ein Tag haben und gut kompilieren. Wenn eine Aufzählung jedoch dasselbe Tag wie eine Struktur hat, ist dies ein Kompilierungsfehler, genau wie 2 Strukturen oder 2 Aufzählungen mit demselben Tag. Sie vergessen auch, dass Labels für goto ein separater Namespace sind. Ein Label kann den gleichen Namen wie ein Tag oder eine Kennung haben, aber keinen Typ, und eine Kennung kann den gleichen Namen wie ein Tag haben, aber keinen Typ.
Rich Jahn
3

Das ist ein bisschen alt, aber ich hoffe, Sie werden den Link, den ich gerade schreibe, zu schätzen wissen, da ich ihn zu Beginn dieses Jahres sehr geschätzt habe.

Hier ist es . Ich sollte die Erklärung zitieren, die mir immer in den Sinn kommt, wenn ich einige böse Typedefs erfassen muss:

In Variablendeklarationen sind die eingeführten Namen Instanzen der entsprechenden Typen. [...] Wenn jedoch das typedefSchlüsselwort vor der Deklaration steht, sind die eingeführten Namen Aliase der entsprechenden Typen

Wie bereits erwähnt, müssen in C ++ keine typedefs verwendet werden, die Aufzählungen deklarieren . Aber das ist die Erklärung der Syntax des Typedefs! Ich hoffe, es hilft (wahrscheinlich nicht OP, da es fast 10 Jahre her ist, aber jeder, der Schwierigkeiten hat, solche Dinge zu verstehen).

Francisco Orlandini
quelle
1

In einigen C-Codestyle-Anleitungen wird die typedef-Version aus Gründen der "Klarheit" und "Einfachheit" bevorzugt. Ich bin anderer Meinung, weil das typedef die wahre Natur des deklarierten Objekts verschleiert. Tatsächlich verwende ich keine typedefs, da ich beim Deklarieren einer C-Variablen klarstellen möchte, was das Objekt tatsächlich ist. Diese Wahl hilft mir, mich schneller daran zu erinnern, was ein alter Code tatsächlich tut, und hilft anderen, den Code in Zukunft zu pflegen.

AdRiX
quelle
1

Die eigentliche Antwort auf die "Warum" -Frage (die von den vorhandenen Antworten über dieser alten Frage überraschenderweise ignoriert wird) lautet, dass sich diese enumDeklaration wahrscheinlich in einer Header-Datei befindet, die sowohl als C- als auch als C ++ - Code überkompilierbar sein soll (d. H. sowohl in C- als auch in C ++ - Implementierungsdateien enthalten). Die Kunst, solche Header-Dateien zu schreiben, beruht auf der Fähigkeit des Autors, Sprachmerkmale auszuwählen, die in beiden Sprachen die richtige kompatible Bedeutung haben.

Ameise
quelle