konvertierung enum zu integer erlaubt/definiert

Gast #1593253
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 ?!
#1593267
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.
Gast #1593284
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.
Gast #1593325
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...
#1593348
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);
Gast #1593387
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.
#1593432
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.
#1593468
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!
#1593566
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.
Moderator Persönliche Seite #1593589
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. ä.
Persönliche Seite #1593659
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.
Moderator Persönliche Seite #1593715
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.
Persönliche Seite #1593782
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 ---
#1593809
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren