Forum: Compiler & IDEs konvertierung enum zu integer erlaubt/definiert


von klaus (Gast)


Lesenswert?

Hallo zusammen,

mich interessiert ob es offiziell erlaubt/sicher ist, in C ein enum Typ 
einem Integer zuzuweisen.

Also Beispiel:
1
enum TEST_E
2
{
3
  WERT_A = 0,
4
  WERT_B,
5
  WERT_C,
6
  WERT_D
7
};
8
9
enum TEST_E x;
10
int y;
11
y = (int)WERT_C;  // is it secure to assume y is always 2 ?!

von Stefan E. (sternst)


Lesenswert?

K&R:
1
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.

von Sven P. (Gast)


Lesenswert?

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.

von Peter (Gast)


Lesenswert?

Sven P. schrieb:
> Enums sind eines der Dinge, die schon seit Anbeginn von C prinzipbedingt
> kaputt sind...

was hast du gegen enums?

von Sven P. (Gast)


Lesenswert?

Sie machen den Namensraum schmutzig, es gibt keine Typprüfung. 
Eigentlich sind die ziemlich überflüssig :-/

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Hc Z. (mizch)


Lesenswert?

Seit "Anbeginn von C" können enums nicht defekt sein, denn die kamen 
erst deutlich später ...

von klaus (Gast)


Lesenswert?

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...

von Uwe .. (uwegw)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

Trotzdem kann man sich noch darauf verlassen, daß eine enum
technisch einer int entspricht und eine Typumwandlung
hin und her funktioniert.

von Rolf Magnus (Gast)


Lesenswert?

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.

von klaus (Gast)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

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
enum GeometryType { Square, Rectangle, Circle };
4
enum Color        { Red, Blue, Green };
5
6
int main()
7
{
8
  enum Color color;
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.

von Klaus W. (mfgkw)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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!

von Sven P. (Gast)


Lesenswert?

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.

von Klaus W. (mfgkw)


Lesenswert?

Außerdem kann man den Quelltext deutlich lesbarer gestalten:
1
typedef enum
2
  {
3
    UART_parity_none,
4
    UART_parity_even,
5
    UART_parity_odd,
6
  }    UART_parity_t;
7
...
8
  if( parity!=UART_parity_none )...
9
...
10
  uart1_init( 9600, 8, UART_parity_none, 1, UART_mode_write );

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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. ä.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> 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
enum bla
2
{
3
  fusel,
4
  blub,
5
  funz
6
};
7
8
int machwas(enum bla so);


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
int machwas(int so);

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
typedef int machwas_t;
2
/* possible values of machwas_t: */
3
#define fusel 0
4
#define blub 1
5
#define funz 2
6
7
int machwas(machwas_t so);

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> 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
typedef enum 
2
{
3
  fusel,
4
  blub,
5
  funz
6
} bla;
7
8
int machwas(bla so);

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

von klaus (Gast)


Lesenswert?

3, 2, 1, Battle ;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nö. Das nun nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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...

von (prx) A. K. (prx)


Lesenswert?

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> 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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.