The identifiers in an enumerator list are declared
2
as constants of type int, and may appear wherever
3
constants are required.
PS: Damit ist auch der Type-Cast überflüssig.
PS2:
Und auch die enum Variable (x) ist nichts weiter als ein int.
"x = 100;" würde nicht mal eine Warnung geben.
Enums sind eines der Dinge, die schon seit Anbeginn von C prinzipbedingt
kaputt sind...
Aber ja, es sind einfach nur Ganzzahlen. Manche Bücher empfehlen sogar,
ganzzahlige (int) Konstanten nicht mit #define, sondern als Enum zu
vereinbaren.
Zitat aus dem C99-Draft:
1
The identifiers in an enumerator list are declared as constants that have type int and
2
may appear wherever such are permitted.107) An enumerator with = defines its
3
enumeration constant as the value of the constant expression. If the first enumerator has
4
no =, the value of its enumeration constant is 0. Each subsequent enumerator with no =
5
defines its enumeration constant as the value of the constant expression obtained by
6
adding 1 to the value of the previous enumeration constant. (The use of enumerators with
7
= may produce enumeration constants with values that duplicate other values in the same
8
enumeration.) The enumerators of an enumeration are also known as its members.
Peter schrieb:
> was hast du gegen enums?
Dass es halt kein eigenständiger Typ ist. Ist letztlich nur eine
Debug-Hilfe: der Debugger kann die Symbole statt nur Zahlen dafür
anzeigen. Das ist in C praktisch der einzige Unterschied zu einem
#define.
C++ ist da besser, dort ist ein enum ein eigenständiger Typ.
Jörg Wunsch schrieb:
> C++ ist da besser, dort ist ein enum ein eigenständiger Typ.
Heißt die Zuweisung eines enum Wertes an einen int sollte man in C++
vermeiden ? Bzw. dort ist dann nicht mehr klar definiert, wie ein enum
auf ein int abgebildet wird?
Vielleicht erkläre ich auch mal den Hintergrund der Frage:
Bei der Programmierung von Mikrocontrollern verwende ich enums wenn man
bei Funktionen zwischen unterschiedlichen Einstellungen wählen kann.
Also Beispiel:
1
enum UART_BITS_E
2
{
3
UART_BITS_7 = 0,
4
UART_BITS_8,
5
UART_BITS_9
6
};
Soll dem Benutzer der Funktion einfach sofort klar machen, welche Werte
erlaubt sind und was sie bedeuten.
Nun will man in der Funktion anhand des enum Wertes ein Register
beschreiben. Entweder man kann sich darauf verlassen, dass ein enum Wert
klar auf ein int abgebildet werden kann, dann kann man die Werte des
enums geeignet wählen und diese direkt in das Register schreiben.
Andernfalls bräuchte man "switch() / case" Gräber...
In diesem Fall würde ich möglichst noch prüfen, ob ein anderer int-Wert
an deine Funktion übergeben wurde. Es besteht ja für die Nutzer kein
Zwang, die Werte aus dem enum zu verwenden. Speziell in deinem Beispiel
könnte man ja auch schnell mal auf die Idee kommen, eine 7, 8 oder 9
direkt zu übergeben. Also setUartBits(7); statt
setUartBits(UART_BITS_7);
klaus schrieb:
> Heißt die Zuweisung eines enum Wertes an einen int sollte man in C++> vermeiden?
Nicht "sollte", sondern "muss". Man darf dort einen enum nicht
einfach an einen int zuweisen, dafür bedarf es eines typecasts
(mit dem man dann die Verwantwortung für sein Tun gegenüber dem
Compiler übernimmt ;-).
Jörg Wunsch schrieb:
[C++]
> Man darf dort einen enum nicht einfach an einen int zuweisen, dafür> bedarf es eines typecasts (mit dem man dann die Verwantwortung für sein> Tun gegenüber dem > Compiler übernimmt ;-).
Da muß ich widersprechen. Man darf einen enum genauso wie in C an einen
int zuweisen. Umgekehrt gilt das allerdings nicht. Die Zuweisung int ->
enum ist (ohne Cast) verboten.
Okay also schonmal vielen Dank für die Antworten.
Ich versuche mich mal an einer Zusammenfassung:
C++:
enum -> int (OK)
int -> enum (ERR!)
C:
enum -> int (OK)
int -> enum (OK)
klaus schrieb:
> Okay also schonmal vielen Dank für die Antworten.> Ich versuche mich mal an einer Zusammenfassung:>> C++:> enum -> int (OK)> int -> enum (ERR!)>> C:> enum -> int (OK)> int -> enum (OK)
Wobei diese Fälle sogar noch die Harmloseren sind.
Wie Jörg schon sagte sind enums seit ihrer Einführung in C kaputt
1
#include<stdio.h>
2
3
enumGeometryType{Square,Rectangle,Circle};
4
enumColor{Red,Blue,Green};
5
6
intmain()
7
{
8
enumColorcolor;
9
10
color=Square;
11
}
compiliert in C (leider) anstandslos.
Damit ist der ganze Vorteil den man sich durch die Einführung von enums
verspricht, zb das man den Benutzer einer Funktion auf bestimmte
vorgegebene Funktionsargumente festnageln kann, dahin.
Erzähl das einmal einem Pascal-Jünger. Der lacht sich schief und
scheckig.
Daß Pascal und C gewisse Unterschiede haben, ist
ja nicht neu. :-)
Würdest du Pascal für MC nehmen wollen und auf alle
kleinen Schweinereien verzichten müssen?
Klaus Wachtler schrieb:
> Würdest du Pascal für MC nehmen wollen und auf alle> kleinen Schweinereien verzichten müssen?
LOL. Mit Sicherheit nicht!
Aber speziell dieser enum ist mir gerade beim Umstieg auf C 'unangenehm
aufgefallen'. Da baust du dir voller Enthusiasmus und mit den besten
Erwartungen die tollsten enums und stellst dann fest: Alles für die Katz
:-)
Aber: Man gewöhnt sich an alles. Nur nicht am Dativ!
Naja, ganz für die Katz sind die ja nich -- zumindest der GCC spuckt
schonmal Warnungen aus, wenn man z.B. einen Aufzählungswert in einem
switch()-Dinge vergisst.
Mehr kann man halt bei C nicht verlangen.
Woanders geht C ja genauso offenherzig mit Typkonvertierung
um, insofern ist das eigentlich kein Problem von enum.
Klaus Wachtler schrieb:
> Außerdem kann man den Quelltext deutlich lesbarer gestalten:
Das ging aber auch schon mit einem #define. Wie schon geschrieben,
der einzige Vorteil eines enum gegenüber dem #define ist, dass der
Debugger was davon erfährt (vom #define erfährt er rein gar nichts).
Dem gegenüber steht der Nachteil, dass die Größe eines enum vom
C-Standard nicht vorgegeben ist (außer dass alle aufgezählten
Elemente halt rein passen müssen), und dass es keine standardmäßige
Methode gibt, wie man die Größe ggf. anpassen kann. So reserviert
der GCC by default einen `int', man kann es aber mit _attribute_
((packed)) auf die minimal notwendige Größe zusammen streichen
lassen, während ein IAR nur letzteres kann, das aber halt ohne
irgendwelche Compilerschalter, pragmas o. ä.
> Das ging aber auch schon mit einem #define. Wie schon geschrieben,> der einzige Vorteil eines enum gegenüber dem #define ist, dass der> Debugger was davon erfährt (vom #define erfährt er rein gar nichts).
Nun, wird beispielsweise ein Funktionsprototyp mit einem enum
deklariert, ist es dem Compiler zwar nach wie vor schnuppe, was
übergeben wird, aber der Anwender hat die Chance, klar zu erkennen,
welche Werte potentiell zulässig sind.
1
enumbla
2
{
3
fusel,
4
blub,
5
funz
6
};
7
8
intmachwas(enumblaso);
Das ist bei Angabe eines int und Nutzung von #defines nicht der Fall.
Hier ist zusätzliche Dokumentation nötig.
1
#define fusel 0
2
#define blub 1
3
#define funz 2
4
5
intmachwas(intso);
Die Zuordnung, daß diese #define-Werte für den Funktionsparameter zu
nutzen sind, die ist nicht "automatisch" gegeben, was sie bei Gebrauch
des enums ist.
Rufus t. Firefly schrieb:
> Das ist bei Angabe eines int und Nutzung von #defines nicht der Fall.> Hier ist zusätzliche Dokumentation nötig.
Geht auch mit einem zusätzlichen Typ:
1
typedefintmachwas_t;
2
/* possible values of machwas_t: */
3
#define fusel 0
4
#define blub 1
5
#define funz 2
6
7
intmachwas(machwas_tso);
Würden die meisten Leute wohl ohnehin auch für einen enum machen,
weil der ohne das Wort "enum" in C wiederum kein eigenständiger
Typname ist.
> Geht auch mit einem zusätzlichen Typ:
Das setzt aber wiederum voraus, daß die #define-Werte und der Kommentar
an der richtigen Stelle der Headerdatei untergebracht werden. Es ist
schon einen Schritt besser als die Kombination "int und #defines", aber
setzt immer noch das Einhalten der Konvention durch den Schreiber der
Headerdatei voraus.
Beim enum (oder typedef enum) wird das erzwungen.
Und daß die meisten Leute ein typedef verwenden, ändert an diesem
Sachverhalt nichts.
1
typedefenum
2
{
3
fusel,
4
blub,
5
funz
6
}bla;
7
8
intmachwas(blaso);
Natürlich wäre es noch besser, wenn der Compiler an so einer Stelle auch
noch eine Typüberprüfung machen würde und zumindest eine Warnung
ausspuckte, aber andererseits: Wir programmieren in C, damit wir
Pascal/Modula/Oberon oder Ada vermeiden können ---
Rufus t. Firefly schrieb:
> Und daß die meisten Leute ein typedef verwenden, ändert an diesem> Sachverhalt nichts.
Du musst mich nicht vom Sinn von enums überzeugen :), trotzdem finde
ich sie halt nur halbherzig implementiert.
Ada wollte ich mir schon immer mal ansehen, ist aber auch beim
Wollen geblieben...
Jörg Wunsch schrieb:
> Das ging aber auch schon mit einem #define. Wie schon geschrieben,> der einzige Vorteil eines enum gegenüber dem #define ist,
Ein weiterer Vorteil ist der Namensraum. Der Name eines enum kann lokal
neu vergeben werden und das wird ggf. mit einem freundlichem sehr
zielführenden Hinweis des Compilers garniert. Bei einem #define geht das
nicht und es führt zu den seltsamsten Fehlermeldungen.
Besser ist freilich das "const" in C++ bei Integers.
> Du musst mich nicht vom Sinn von enums überzeugen :),
Nee, Missionieren ist auch nicht mein Ding.
> trotzdem finde ich sie halt nur halbherzig implementiert.
Das sehe ich nicht anders, s.o.
Nur bieten sie trotz ihrer Defizite in manchen Situationen doch gewisse
Vorteile gegenüber #defines.