www.mikrocontroller.net

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


Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

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

Also Beispiel:
enum TEST_E
{
  WERT_A = 0,
  WERT_B,
  WERT_C,
  WERT_D
};

enum TEST_E x;
int y;
y = (int)WERT_C;  // is it secure to assume y is always 2 ?!

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
K&R:
The identifiers in an enumerator list are declared
as constants of type int, and may appear wherever
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.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
The identifiers in an enumerator list are declared as constants that have type int and
may appear wherever such are permitted.107) An enumerator with = defines its
enumeration constant as the value of the constant expression. If the first enumerator has
no =, the value of its enumeration constant is 0. Each subsequent enumerator with no =
defines its enumeration constant as the value of the constant expression obtained by
adding 1 to the value of the previous enumeration constant. (The use of enumerators with
= may produce enumeration constants with values that duplicate other values in the same
enumeration.) The enumerators of an enumeration are also known as its members.


Autor: Peter (Gast)
Datum:

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

was hast du gegen enums?

Autor: Sven P. (haku) Benutzerseite
Datum:

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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hc Zimmerer (mizch)
Datum:

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

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
enum UART_BITS_E
{
  UART_BITS_7 = 0,
  UART_BITS_8,
  UART_BITS_9
};

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

Autor: Uwe ... (uwegw)
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 ;-).

Autor: Klaus Wachtler (mfgkw)
Datum:

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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <stdio.h>

enum GeometryType { Square, Rectangle, Circle };
enum Color        { Red, Blue, Green };

int main()
{
  enum Color color;

  color = Square;
}

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.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Außerdem kann man den Quelltext deutlich lesbarer gestalten:
typedef enum
  {
    UART_parity_none,
    UART_parity_even,
    UART_parity_odd,
  }    UART_parity_t;
...
  if( parity!=UART_parity_none )...
...
  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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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. ä.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.
enum bla
{
  fusel,
  blub,
  funz
};

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.
#define fusel 0
#define blub 1
#define funz 2

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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
typedef int machwas_t;
/* possible values of machwas_t: */
#define fusel 0
#define blub 1
#define funz 2

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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.
typedef enum 
{
  fusel,
  blub,
  funz
} bla;

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

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
3, 2, 1, Battle ;-)

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nö. Das nun nicht.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.