mikrocontroller.net

Forum: Compiler & IDEs Define in Enumeration?


Autor: Klasss (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

In dem Header zu epoll (epoll.h; z.B. hier 
http://www.danga.com/memcached/dist/epoll.h) bin ich über folgende 
Enumeration gestoßen:
enum EPOLL_EVENTS
  {
    EPOLLIN = 0x001,
#define EPOLLIN EPOLLIN
    EPOLLPRI = 0x002,
#define EPOLLPRI EPOLLPRI
    EPOLLOUT = 0x004,
#define EPOLLOUT EPOLLOUT
    EPOLLRDNORM = 0x040,
#define EPOLLRDNORM EPOLLRDNORM
    EPOLLRDBAND = 0x080,
#define EPOLLRDBAND EPOLLRDBAND
    EPOLLWRNORM = 0x100,
#define EPOLLWRNORM EPOLLWRNORM
    EPOLLWRBAND = 0x200,
#define EPOLLWRBAND EPOLLWRBAND
    EPOLLMSG = 0x400,
#define EPOLLMSG EPOLLMSG
    EPOLLERR = 0x008,
#define EPOLLERR EPOLLERR
    EPOLLHUP = 0x010,
#define EPOLLHUP EPOLLHUP
    EPOLLET = (1 << 31)
#define EPOLLET EPOLLET
  };

Was haben den diese #defines in der Enumeration zu suchen und warum 
macht man so etwas überhaupt?

Danke & Grüße
Klasss

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Meine Vermutung wäre: Damit man per #ifdef prüfen kann, ob bestimmte 
Elemente existieren.

Autor: eagle user (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
eagle user schrieb:
> Für mich ist das ein weiterer Grund, #define zu vermeiden.

Wie würdest du dieses Problem denn ohne #define lösen?

Autor: meckerziege (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Wo liegt das Problem? Das define sieht eh nur der präprozessor. Danach 
ists weg.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
meckerziege schrieb:
> Wo liegt das Problem? Das define sieht eh nur der präprozessor. Danach
> ists weg.

Warum dann C/C++/Assembler?  Das sieht eh nur Compiler/Assembler, danach 
ist's weg.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
meckerziege schrieb:
> Wo liegt das Problem?

Es geht um die glibc, die in verschiedenen Versionen vorliegen kann, und 
nicht alle Elemente des obigen enum gibt es in jeder Version. Die 
#defines sorgen dafür, dass ein Programm mit den unterschiedlichen 
Versionen zusammen funktionieren kann, indem es per #ifdef nur die 
Elemente benutzt, die auch tatsächlich verfügbar sind.
Man kann in C nicht Teile des Code abhängig davon weglassen, ob ein 
bestimmtes enum-Element exisitert oder nicht, aber mit Makros geht das.

meckerziege schrieb:
> Das define sieht eh nur der präprozessor.

Genau für den ist es ja auch bestimmt.

Autor: eagle user (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Rolf M. schrieb:
> eagle user schrieb:
>> Für mich ist das ein weiterer Grund, #define zu vermeiden.
>
> Wie würdest du dieses Problem denn ohne #define lösen?

Möglicherweise hätte es dieses Problem nie gegeben, wenn niemand 
"#define EPOLLIN 1" benutzt hätte. Jetzt geht es wohl nicht mehr ohne. 
Für die ganzen CONFIG_FOO im Kernel ist #if und #define wohl auch 
praktisch, das sehe ich schon ein. Aber in meinen Programmen möchte ich 
den preprocessor möglichst sparsam nutzen.

Autor: Joachim K. (minifloat)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Dem Präprozessor sind die Enum-Elemente und auch deren Zahlenwert 
bekannt.
Sowas hier...
typedef enum
{
  MyEnumFoo,
  MyEnumBar,
  MyEnum2,
  MyEnum3,
  MyEnum4,
  MyEnum5,
  MyEnum6,
  MyEnum7,
  MyEnum8,
  MyEnum9,
  MyEnumA,
  MyEnumNumOf
} MyEnumType;

#if(MyEnumNumOf <= 8)
typedef uint8_t MyBitGeFummelType;
#elif(MyEnumNumOf <= 16)
typedef uint16_t MyBitGeFummelType;
#else
#error Mehr als 16bit mag ich jetz nicht
#endif

/* Die Bits in MyVar haben jetzt Namen und MyVar hat die nötige Bitbreite */
MyBitGeFummelType MyVar;
..habe ich zur Zeit im Einsatz. Wäre ja doof, wenn das nicht kompiliert. 
Ich wage aber die These aufzustellen, dass das nicht jeder Compiler so 
frisst.

Rolf M. schrieb:
> Man kann in C nicht Teile des Code abhängig davon weglassen, ob ein
> bestimmtes enum-Element exisitert oder nicht, aber mit Makros geht das.
Man kann doch die korrespondierende Funktionalität totlegen und zB. in 
einen Fehlerzustand gehen? Damit bleibt die Interface-definition (= das 
Enum) gleich, es gibt halt nur nicht alles.

Schöner als im Ausgangsposting wäre es aber, die #define unter die 
Enum-Definition zu packen.

mfg mf

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
eagle user schrieb:
> Rolf M. schrieb:
>> eagle user schrieb:
>>> Für mich ist das ein weiterer Grund, #define zu vermeiden.
>>
>> Wie würdest du dieses Problem denn ohne #define lösen?
>
> Möglicherweise hätte es dieses Problem nie gegeben, wenn niemand
> "#define EPOLLIN 1" benutzt hätte. Jetzt geht es wohl nicht mehr ohne.

Nein, darum geht es gar nicht. Es geht um die Erkennung, ob es überhaupt 
existiert.
Sagen wir mal, in Version X gab es das enum-Element EPOLLERR noch nicht. 
Das wurde in Version X+1 hinzugefügt. Ich muss jetzt ein Programm 
schreiben, das dieses auf Version X+1 benutzt, aber auch fehlerfrei 
durch den Compiler läuft, wenn ich Version X nutzen will. Ohne #define 
kann ich nicht erkennen, ob es das enum-Element EPOLLERR gibt oder 
nicht. Und wenn mein Programm es einfach benutzt, obwohl es nicht 
existiert, bricht der Compiler mit Fehler ab.

Joachim K. schrieb:
> Dem Präprozessor sind die Enum-Elemente und auch deren Zahlenwert
> bekannt.

Nein.

> ..habe ich zur Zeit im Einsatz. Wäre ja doof, wenn das nicht kompiliert.

Das solltest du nochmal überdenken. Entferne aus deinem Beispiel mal den 
enum komplett und probiere mal, was dann passiert.

> Ich wage aber die These aufzustellen, dass das nicht jeder Compiler so
> frisst.

Sollte schon, nur tut es nicht das, was du erwartest.

> Rolf M. schrieb:
>> Man kann in C nicht Teile des Code abhängig davon weglassen, ob ein
>> bestimmtes enum-Element exisitert oder nicht, aber mit Makros geht das.
> Man kann doch die korrespondierende Funktionalität totlegen und zB. in
> einen Fehlerzustand gehen?

Dazu müsste man aber schon von Anfang an wissen, was in späteren 
Versionen alles mal dazu kommen wird.

Autor: Joachim K. (minifloat)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
>> ..habe ich zur Zeit im Einsatz. Wäre ja doof, wenn das nicht kompiliert.
>
> Das solltest du nochmal überdenken. Entferne aus deinem Beispiel mal den
> enum komplett und probiere mal, was dann passiert.

Das Enum im Ursprungspost wird ja auch nie komplett entfernt, sondern 
nur erweitert. Mein Konstrukt tut schon was es soll. Ich sehe im disasm, 
mapfile, Debugger, ... , dass der Präprozessor den Wert vom numof wohl 
doch kannte. Also muss auch der der anderen Enum-Elemente bekannt sein. 
Ich werde das mal testen...

Rolf M. schrieb:
> Ohne #define kann ich nicht erkennen, ob es das enum-Element EPOLLERR
> gibt oder nicht.

Du kannst mit #if(x==y)\sonstwas\#endif prüfen, ob ein Ding namens 
EPOLLERR den von dir erwarteten Wert besitzt. Wenn nicht, gibt es das 
Feature in der Version der lib, wasweissich, offenbar noch nicht.

Autor: Mikro 7. (mikro77)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joachim K. schrieb:
> Mein Konstrukt tut schon was es soll.

Setz doch mal ein #ifndef vor deiner Abfrage.
...
#if !defined(MyEnumNumOf)
#error Argh!
#elif(MyEnumNumOf <= 8)
...
Mit gcc bekomme ich da "Argh!". ;-)

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Joachim K. schrieb:
> Das Enum im Ursprungspost wird ja auch nie komplett entfernt, sondern
> nur erweitert. Mein Konstrukt tut schon was es soll. Ich sehe im disasm,
> mapfile, Debugger, ... , dass der Präprozessor den Wert vom numof wohl
> doch kannte.

Wenn der Präprozesssor das wirklich tut, also in

#if(MyEnumNumOf <= 8)

für MyEnumNumOf den Wert 11 einsetzt, verstößt er gegen die ISO-Norm,
die besagt:


"After all replacements due to macro expansion and the defined unary
operator have been performed, all remaining identifiers (including those
lexically identical to keywords) are replaced with the pp-number 0"

Da MyEnumNumOf kein Makro ist und deeswegen nicht expandiert werden
kann, zählt es zu den "remaining identifiers" und wird deswegen durch 0
ersetzt. Im #if-#elsif-#else-#endif-Konstrukt wird also wegen 0<=8
unabhängig von der Anzahl der Enum-Elemente immer die erste Alternative

typedef uint8_t MyBitGeFummelType;

verwendet.

Der GCC verhält sich genauso, wie eben beschrieben. Welchen Compiler
verwendest du?

: Bearbeitet durch Moderator
Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joachim K. schrieb:
> Rolf M. schrieb:
>>> ..habe ich zur Zeit im Einsatz. Wäre ja doof, wenn das nicht kompiliert.
>>
>> Das solltest du nochmal überdenken. Entferne aus deinem Beispiel mal den
>> enum komplett und probiere mal, was dann passiert.
>
> Das Enum im Ursprungspost wird ja auch nie komplett entfernt, sondern
> nur erweitert.

Es ging mir nicht um einen Vergleich zum Ursprungsposting. Wenn du aus 
deinem Beispiel den enum komplett entfernst, wird es trotzdem noch 
fehlerfrei compilieren.

> Mein Konstrukt tut schon was es soll. Ich sehe im disasm,
> mapfile, Debugger, ... , dass der Präprozessor den Wert vom numof wohl
> doch kannte.

Da siehst du nirgends, welchen Wert er eingesetzt hat.

> Ich werde das mal testen...

Das solltest du auf jeden Fall tun.

Autor: Oliver S. (oliverso)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joachim K. schrieb:
> Schöner als im Ausgangsposting wäre es aber, die #define unter die
> Enum-Definition zu packen.

Das ist so gleich die Dokumentation, welches Define zu welchem enum 
gehört.

Oliver

Autor: Joachim K. (minifloat)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Welchen Compiler
> verwendest du?

Cosmic, der frisst das so...

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Joachim K. schrieb:
> Yalu X. schrieb:
>> Welchen Compiler
>> verwendest du?
>
> Cosmic, der frisst das so...

Nochmal: Dass er es "frisst", ist normal. Das sollte jeder Compiler tun. 
Aber macht er auch wirklich das, was du dir vorstellst?

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Ich habe der kostenlosen Demoversion des Cosmic-Compilers (COSMIC
Software CORTEX-M C Cross Compiler (LIMITED) V4.1.3) mal den folgenden
Code zum Fraß vorgeworfen:

enum { ZERO, ONE, TWO, THREE, FOUR };

#if THREE == 0
#error "THREE hat den Wert 0"
#elif THREE == 3
#error "THREE hat den Wert 3"
#else
#error "THREE hat einen anderen Wert"
#endif


Ruft man den Compiler ohne irgendwelche Optionen auf, gibt der Compiler
folgende Meldung aus:

#error cpcorm mytest.c:6 "THREE hat den Wert 3"

Wie von Joachim geschrieben, wird in der #if-Direktive für THREE also
tatsächlich die 3 aus dem Enum eingesetzt.

Lässt man aber nur den Präprozessor laufen (Compileroption -sp), lautet
die Meldung

#error cpcorm mytest.c:4 "THREE hat den Wert 0"

Dies zeigt, dass der Präprozessor alleine nicht in der Lage ist, die
Enum-Deklaration zu parsen. Vielmehr scheint im ersten Beispiel (ohne
Optionen) der Präprozessor und der eigentliche C-Parser so ineinander
verwoben zu sein, dass vom C-Parser Informationen (nämlich die Enum-
Werte) in den Präprozessor zurückfließen. Der Datenfluss zwischen
Präprozessor und C-Parser ist also – anders als bei anderen Compilern –
bidirektional.

Etwas seltsam ist es ja schon, dass die sequenzielle Ausführung von
Präprozessor- und Compiler-Phase zu einem anderen Ergebnis führt als die
Ausführung beider Phasen in einem einzelnen Aufruf.

Auch wenn die Auswertung von Enum-Werten im Präprozessor nicht der
ISO-Norm entspricht, scheint dieses Feature absichtlich implementiert
worden zu sein, denn mit der Option -psa (strict ANSI) verhält sich der
Compiler (egal, ob mit oder ohne -sp) wie erwartet:

#error cpcorm mytest.c:4 "THREE hat den Wert 0"

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.