Hallo,
mir tat sich gerade folgende Frage auf:
Warum funktionieren Beispiel 1 und 2 im gegensatz zu BSP 3 ohne Warnung?
1
typedefenum
2
{
3
eFlag0=(1<<0),
4
eFlag1=(1<<1),
5
eFlag2=(1<<2)
6
}eFlag_t;
7
8
9
voidflag_fkt(eFlag_teFlag)
10
{
11
// BSP 1
12
flag_fkt(eFlag0|eFlag1|eFlag2);
13
14
// BSP 2
15
if(eFlag==(eFlag0|eFlag1|eFlag2))
16
{}
17
elseif(eFlag==(eFlag0|eFlag1))
18
{}
19
20
// BSP3 (warning: case value "*" not in enumarated type eFlag_t)
21
switch(eFlag)
22
{
23
case(eFlag0|eFlag1|eFlag2):
24
break;
25
26
case(eFlag0|eFlag1):
27
break;
28
}
29
}
Habe diese Weise den enum typedef als Funktionsparameter zu nutzen von
der LPCopen Bib übernommen. Fand ich ganz praktisch weil man dann sofort
sehen kann was zu übergeben ist und man nicht aus einer Liste von
defines aussuchen muss. Gedanken hierzu wären mir auch willkommen.
Grüße und bitte seid lieb
Ein enum ist einfach nicht dafür da, irgendwelche Flags zu speichern.
Ein enum soll eine Aufzählung an Werten bieten und sorgt dafür dass
diese Werte eine Namen haben, gruppiert sind und vom Compiler geprüft
werden können.
Der konkrete Wert steht nicht im Mittelpunkt eines enums. Auch wenn sie
einen Wert zugewiesen haben.
Bitte einfach mal überlegen ob es Sinn macht, Flags da rein zu stopfen.
Vielleicht erinnerst du dich dass es auch ganz normale Variablen gibt,
die haben auch einen Namen. Niemand muss defines nehmen wenn er nicht
will.
dings schrieb:> // BSP 1> flag_fkt(eFlag0 | eFlag1 | eFlag2);
Kann es sein, dass hier ein Tippfehler drin ist? Du rufst hier die
Funktion von innen heraus nochmal auf.
Hallo,
ohne den Hintergrund zu kennen, macht es vielleicht Sinn bool Typen zu
deklarieren und im Switch Case bewusst Falltrough ausnutzen. Dann hätte
man sowas wie eine ODER Verknüpfung.
Die Rekursion mit dem aufruf von flag_fkt() ergibt natürlich keine Sinn,
ist auch nur ein Beispiel wie man den enum typedef "missbrauchen" kann.
Hätte einfach gerne eine Reihe von Flags (auch mehr als 3) die nur dort
definiert sind wo eben der typedef bekannt ist und das auch am
Funktionsprototyp ersichtlich ist welche Flags in Kombination der
Funktion zu übergeben sind.
Das gibts dann wohl einfach nicht?
Nachtrag:
Jetzt hab ich noch mal was rumprobiert und die Warnung bekomm ich weg
indem ich "switch( (int)eFlag )" schreibe.
(Ach wie oft bin ich schon zwischen c ist toll und c ist kacke hin und
her geschwankt)
dings schrieb:> Nachtrag:> Jetzt hab ich noch mal was rumprobiert und die Warnung bekomm ich weg> indem ich "switch( (int)eFlag )" schreibe.>> (Ach wie oft bin ich schon zwischen c ist toll und c ist kacke hin und> her geschwankt)
Du programmierst Kacke. Das allein ist dein Problem. Sorry das kann C
nun echt nichts dafür.
Du Vergewaltigst den Switch/Case für dein Flag Verorderung. Und
beschwerst dich noch? So ist das ganze einfach nicht gedacht.
Du willst auf KOMBINATIONEN von Flags prüfen. Das kann dein enum aber
gar nicht.
Er kann nur einen Wert der Liste annehmen. Keine Kombinationen.
ja hast ja recht Cyblord. Dann überleg ich mir mal ob ichs kacke mache
oder eben defines nehme. Vermisse einfach das es neben einem "enum" auch
ein "flag" gibt.
Hab das sonst auch nie so gemacht. Hab mir das letztens eben mal
abgeguckt und fands ganz praktisch weil ich so die API sofort
durchschauen konnte wie in welche Funktion Flags zu übergeben sind.
dings schrieb:> ja hast ja recht Cyblord. Dann überleg ich mir mal ob ichs kacke mache> oder eben defines nehme.
Wie wärs mit richtig machen?
> Vermisse einfach das es neben einem "enum" auch> ein "flag" gibt.
Mit "Flags" sind ja eigentlich konstante Bitmasken gemeint. Richtig? Du
kannst dafür entweder defines nehmen oder const Variablen.
Wieso sollte hier was fehlen?
> Hab das sonst auch nie so gemacht. Hab mir das letztens eben mal> abgeguckt und fands ganz praktisch weil ich so die API sofort> durchschauen konnte wie in welche Funktion Flags zu übergeben sind.
Flags als uint irgendwas zu übergeben hat sich bewährt. Machs einfach
so.
Wenn dir das zu low level ist, dann mache high level funktionen die eben
nicht direkt flags bekommen, sondern z.B. ganze Structs mit Bools drin.
Die sind mehr als einfach zu durchschauen. Damit abstrahierst du über
die Flags und deine Funktion baut die Flags aus den Bools und sonstigen
Werten der Struct zusammen. Der Benutzer der Funktion muss dann nichts
über die Flags oder deren Bitpositionen wissen.
Das ist die beste Lösung.
Klaus W. schrieb:> dings schrieb:>> Das mit Structs zu machen ist auch kein schlechter hinweis - Danke.>> Bitfelder wäre hier wahrscheinlich das richtige Stichwort.
Nein.
Nur wenn du um jedes Byte Speicher kämpfst.
dings schrieb:> Hallo,>> mir tat sich gerade folgende Frage auf:> Warum funktionieren Beispiel 1 und 2 im gegensatz zu BSP 3 ohne Warnung?>
Bei Beispiel 1 sollte ein anständiger Compiler schon aussteigen weil das
Ergebnis der Veroderung ein int und kein eFlag_t ist was du übergibst.
Der C Compiler kann nur enum values zu int konvertieren aber nicht
umgekehrt.
Warum packst du nicht alle zulässigen Kombinationen mit ins enum dann
brauchst du keine Klimmzüge machen.
> Sorry das kann C nun echt nichts dafür.
Die Sache hat durchaus einen gewissen Humor.
Kernighan & Ritche entwickelten C gerade deswegen, weil sie in einer
Hochsprache solche Bitfummeleien machen wollten.
Im Prinzip hast du recht. C kann nichts dafür. Schuld sind die Leute,
die seit 40 Jahren immer wieder neue Features an C dranpappen.
Hans-Georg L. schrieb:> Warum packst du nicht alle zulässigen Kombinationen mit ins enum dann> brauchst du keine Klimmzüge machen.
Das können aber ziemlich viele werden, wenn's z.B. 10 Flags sind und
prinzipiell jede Kombination möglich wäre.
dings schrieb:> Das mit Structs zu machen ist auch kein schlechter hinweis - Danke.
Das macht halt die Nutzung ziemlich umständlich, weil man dann nicht
mehr einfach sowas schreiben kann wie:
Rolf M. schrieb:> Hans-Georg L. schrieb:>> Warum packst du nicht alle zulässigen Kombinationen mit ins enum dann>> brauchst du keine Klimmzüge machen.>> Das können aber ziemlich viele werden, wenn's z.B. 10 Flags sind und> prinzipiell jede Kombination möglich wäre.>
Dann kannst du dir aussuchen einen Fehler in einem zentralen enum mit
1024 Einträgen oder in 1024 im Programm verstreuten Funktionaufrufen zu
suchen.
Mit einem enum zeigt dir schon der Compiler eine nicht zulässige
Kombination sonst bekommst du (hoffentlich) eine Laufzeit Fehlermeldung
z.B. aus einem default Zweig einer switch Anweisung und das vielleicht
erst beim Kunden weil es selten auftritt.
Beispiele für viele Kombinationen sind Fehlercodes, Handles, IDs, da
kommt auch kein Mensch auf die Idee das mit Bit Veroderung zu machen da
nimmt man zentrale enum und gut ist.
> da nimmt man zentrale enum und gut ist.
Ja. Guter Standpunkt.
Mag ja sein, die Leute, die den C Standard erweiterten, hatten das so
nicht vorgesehen. Trotzdem ist es ein gutes und sinnvolles Design
Pattern.
Das meiste funktioniert ja mit dem automatischen enum nach int cast. Ab
und zu muss man halt explizit casten.
Wir sollten diese Diskussion an die ISO weiter leiten. Damit wir im
nächsten C Standard offiziell enums als Bitfelder nutzen können.
Noch ein Kommentar schrieb:>> da nimmt man zentrale enum und gut ist.>> Ja. Guter Standpunkt.>> Mag ja sein, die Leute, die den C Standard erweiterten, hatten das so> nicht vorgesehen. Trotzdem ist es ein gutes und sinnvolles Design> Pattern.>> Das meiste funktioniert ja mit dem automatischen enum nach int cast. Ab> und zu muss man halt explizit casten.>> Wir sollten diese Diskussion an die ISO weiter leiten. Damit wir im> nächsten C Standard offiziell enums als Bitfelder nutzen können.
Die werden für diese Idee ein mildes lächeln übrig haben ;-) Keine
Angst, da wurde nichts verpasst oder verschlafen ;-)
In C musst du mit den Bitfeldern in Strukturen und ihren Nachteilen
leben.
In C++ gibt es Bitfelder in der Stdlib aber auch (noch) nicht ideal, für
diesen Zweck, geeignet ...
Was ich mir im C++ Standard wünsche wäre die Abfrage während der
Compilezeit ob ein Wert im enum enthalten ist oder nicht. Wird aber
schon diskutiert ...
Hans-Georg L. schrieb:> Dann kannst du dir aussuchen einen Fehler in einem zentralen enum mit> 1024 Einträgen oder in 1024 im Programm verstreuten Funktionaufrufen zu> suchen.
Warum das?
> Mit einem enum zeigt dir schon der Compiler eine nicht zulässige> Kombination sonst bekommst du (hoffentlich) eine Laufzeit Fehlermeldung
Wenn Flags unabhängig sind, dann werden genau dies vorkommen. Wenn es
keine Flags sind, dann sollte man auch keine verwenden
> Beispiele für viele Kombinationen sind Fehlercodes, Handles, IDs, da> kommt auch kein Mensch auf die Idee das mit Bit Veroderung zu machen da> nimmt man zentrale enum und gut ist.
Entweder man hat einen Skalar (enum, int, handle, ...) oder Flags
(bitfelder, Masken, Kombinationen, ...). Für beide gibt es gute
Praktiken. Man sollte das aber nicht verwechseln.
Erinnert ihr euch noch an den Spruch von Andrew Tannenbaum?
Enum-Bitfelder waren ein Fortschritt gegenüber allen vorherigen und
allen nachfolgenden Lösungen.
A. S. schrieb:> Hans-Georg L. schrieb:>> Dann kannst du dir aussuchen einen Fehler in einem zentralen enum mit>> 1024 Einträgen oder in 1024 im Programm verstreuten Funktionaufrufen zu>> suchen.> Warum das?
weil er von 10 bit flags geschrieben hat ...
Hans-Georg L. schrieb:> A. S. schrieb:>> Hans-Georg L. schrieb:>>> Dann kannst du dir aussuchen einen Fehler in einem zentralen enum mit>>> 1024 Einträgen oder in 1024 im Programm verstreuten Funktionaufrufen zu>>> suchen.>> Warum das?> weil er von 10 bit flags geschrieben hat ...
Warum "1024 im Programm verstreute Funktionsaufrufe"? Im Extremfalls
sind es 10 stellen, an denen 10 Flags gesetzt werden, und x Masken die
Ausgewertet werden.
Oft erschlägt das erste Flag (an/aus) schon eine Hälfte der
Kombinationen, und das nächste (aktiv/idle) vom Rest noch eine Hälfte.
Trotzdem können alle vorkommen (aus & Error & Overrun), egal ob gewollt
(zur Diagnose) oder als Fehler
A. S. schrieb:> Warum "1024 im Programm verstreute Funktionsaufrufe"? Im Extremfalls> sind es 10 stellen, an denen 10 Flags gesetzt werden, und x Masken die> Ausgewertet werden.>> Oft erschlägt das erste Flag (an/aus) schon eine Hälfte der> Kombinationen, und das nächste (aktiv/idle) vom Rest noch eine Hälfte.> Trotzdem können alle vorkommen (aus & Error & Overrun), egal ob gewollt> (zur Diagnose) oder als Fehle
Mit 10bit kannst du zahlen von 0.. 1023 darstellen ...
Hans-Georg L. schrieb:> Bei Beispiel 1 sollte ein anständiger Compiler schon aussteigen weil das> Ergebnis der Veroderung ein int und kein eFlag_t ist was du übergibst.> Der C Compiler kann nur enum values zu int konvertieren aber nicht> umgekehrt.
Nö. enums in C sind zwar eigene Typen, aber kompatibel zu int (oder
einem anderen Ganzzahl-Typ), und das in alle Richtungen.
In C++ ist das anders, aber ein anständiger C-Compiler wird sich
weigern, C++-Code zu übersetzen.
Oliver
Hans-Georg L. schrieb:> Mit 10bit kannst du zahlen von 0.. 1023 darstellen
Ja. Darum wäre so ein enum Wahnsinn. Zu Anfang hättest Du für mich den
Eindruck erweckt, als fändest Du das besser als Flags.
Oliver S. schrieb:> Hans-Georg L. schrieb:>> Bei Beispiel 1 sollte ein anständiger Compiler schon aussteigen weil das>> Ergebnis der Veroderung ein int und kein eFlag_t ist was du übergibst.>> Der C Compiler kann nur enum values zu int konvertieren aber nicht>> umgekehrt.>> Nö. enums in C sind zwar eigene Typen, aber kompatibel zu int (oder> einem anderen Ganzzahl-Typ), und das in alle Richtungen.
Um das etwas klarer zu machen:
1
6.7.2.2 Enumeration specifiers
2
[...]
3
4) Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined,130) but shall be capable of representing the values of all the members of the enumeration.
Das hilft aber erstmal nicht viel bei der Konvertierung. Anders dagegen
1
6.2.5 Types
2
[...]
3
14) The type char, the signed and unsigned integer types, and the enumerated types are collectively called integer types.
Es gibt Regeln für die Konvertierung zwischen verschiedenen "integer
types".
Hans-Georg L. schrieb:> A. S. schrieb:>>> Warum "1024 im Programm verstreute Funktionsaufrufe"? Im Extremfalls>> sind es 10 stellen, an denen 10 Flags gesetzt werden, und x Masken die>> Ausgewertet werden.>>>> Oft erschlägt das erste Flag (an/aus) schon eine Hälfte der>> Kombinationen, und das nächste (aktiv/idle) vom Rest noch eine Hälfte.>> Trotzdem können alle vorkommen (aus & Error & Overrun), egal ob gewollt>> (zur Diagnose) oder als Fehle> Mit 10bit kannst du zahlen von 0.. 1023 darstellen ...
Mit 10 Bit kann ich 10 Flags darstellen. Der Vorschlag, jede der
möglichen 1024 Kombination dieser Flags getrennt zu behandeln, kam von
dir.
Nehmen wir mal als Beispiel das Öffnen einer Datei. Da gibt's vielleicht
ein Flag, mit dem man sagt, dass sie zum lesen geöffnet werden soll,
eins zum schreiben, eins um das Caching zu deaktivieren, eins um
anzugeben, ob ein anderes Programm die Datei gleichzeitig auch öffnen
darf u.s.w.
Da will ich halt für jedes der 10 Flags eine Stelle, wo ich das handhabe
und nicht eine für jede der 1024 Kombinationen aus den Flags.
Rolf M. schrieb:> Da will ich halt für jedes der 10 Flags eine Stelle, wo ich das handhabe> und nicht eine für jede der 1024 Kombinationen aus den Flags.
Kommt drauf an...
Will man logische Zuordnungen oder Speicher sparen?
10 Flags = 10 Bit = mindestens uint16_t (2 Byte)
10 Zustände = 4 Bit = uint8_t (und noch eine Menge mehr Platz)
Wenn du wenig Speicher hast, dann speicherst du eine Zahl die das
gleiche wie ein Flag aussagt, nicht als einzelne Stellen, sondern als
Wert.
Bsp:
// Nutzt 6 Byte
char a[] = {'1', '2', '3', '4', '5', '6'};
vs.
// Nutzt 4 Byte
uint32_t a = 123456;
Adam P. schrieb:> 10 Flags = 10 Bit = mindestens uint16_t (2 Byte)> 10 Zustände = 4 Bit = uint8_t (und noch eine Menge mehr Platz)
10 Flags und 10 Zustände sind so verschieden wie Äpfel und Sonnentage.
Es macht wenig Sinn, das zu verwischen.
Rolf M. schrieb:> Hans-Georg L. schrieb:>> Warum packst du nicht alle zulässigen Kombinationen mit ins enum dann>> brauchst du keine Klimmzüge machen.>> Das können aber ziemlich viele werden, wenn's z.B. 10 Flags sind und> prinzipiell jede Kombination möglich wäre.>
Du hattest geschrieben jede Kombination möglich ...
und darauf hatte ich geantwortet ...
lass gut sein ...
Aber da die typedef enums in C keine "echten Datentypen" sind ...
macht es überhaupt keinen Sinn einen typedef enum als Parameter zu
benutzen.
Weil man da lustig alles reinhauen kann was nach int konvertierbar ist.
Ich bleibe bei meinem C++ und hasse ab sofort C enums ;-)
Hans-Georg L. schrieb:> Was ich mir im C++ Standard wünsche wäre die Abfrage während der> Compilezeit ob ein Wert im enum enthalten ist oder nicht. Wird aber> schon diskutiert ...
Gibts schon. Stichwort enum class ...
Hans-Georg L. schrieb:> Aber da die typedef enums in C keine "echten Datentypen" sind ...> macht es überhaupt keinen Sinn einen typedef enum als Parameter zu> benutzen.> Weil man da lustig alles reinhauen kann was nach int konvertierbar ist.
Na eben nicht. Darum dreht sich doch der thread. Dass der Compiler da
meckert.
Also Du bestimmst das in C wie du willst.
A. S. schrieb:> Na eben nicht. Darum dreht sich doch der thread.
Ich dachte, um die Frage ganz oben. :-)
> Dass der Compiler da> meckert.
Bei mir nicht, mein gcc übersetzt das ohne Murren.
(mit -std=c90 stört er sich an den C++-Kommentaren, aber das ist ein
anderes Thema).
Zu der Frage, ob man das so machen sollte (case (eFlag0 | eFlag1 |
eFlag2)...):
Wenn man sich im Klaren darüber ist, was man macht und es zur Anwendung
passt - warum nicht. Auch wenn es nicht jedem gefällt.
Tipp:
Man kann sich auch gleich das enum entsprechend zuschneidern:
1
typedefenum
2
{
3
eFlag0=(1<<0),
4
eFlag1=(1<<1),
5
eFlag2=(1<<2),
6
eFlagAlleDrei=eFlag0|eFlag1|eFlag2
7
}eFlag_t;
Dann geht auch ein case eFlagAlleDrei...
Daß man so etwas in C++ evtl. schöner formulieren kann, geschenkt...
Hans-Georg L. schrieb:> Rolf M. schrieb:>> Hans-Georg L. schrieb:>>> Warum packst du nicht alle zulässigen Kombinationen mit ins enum dann>>> brauchst du keine Klimmzüge machen.>>>> Das können aber ziemlich viele werden, wenn's z.B. 10 Flags sind und>> prinzipiell jede Kombination möglich wäre.>>>> Du hattest geschrieben jede Kombination möglich ...
Das heißt aber nicht, dass ich jede Kombination getrennt verarbeiten
will. In der Regel benutze ich ja Flags, weil ich mehrere Dinge damit
angeben will, die mehr oder weniger unabhängig von einander sind. Daher
interessieren mich die vielen möglichen Kombinationen gar nicht. Mich
interessiert jedes Flag für sich alleine. Gerade deshalb halte ich es ja
für wenig sinnvoll, einen eigenen Namen für jede einzelne dieser
Kombinationen zu vergeben.
> Aber da die typedef enums in C keine "echten Datentypen" sind ...> macht es überhaupt keinen Sinn einen typedef enum als Parameter zu> benutzen.
Das typedef kannst du weglassen, das hat damit nichts zu tun. Und warum
sollten enums keine echten Datentypen sein oder nicht geeignet für
Parameter?
> Weil man da lustig alles reinhauen kann was nach int konvertierbar ist.
Es gibt eine implizite Konvertierung von und nach enum-Typen. Ideal ist
das nicht, das stimmt.
Klaus W. schrieb:> A. S. schrieb:>>> Na eben nicht. Darum dreht sich doch der thread.>> Ich dachte, um die Frage ganz oben. :-)>> Dass der Compiler da>> meckert.>> Bei mir nicht, mein gcc übersetzt das ohne Murren
Eben. Jeder wie er mag. Wer "Typsicherheit" will, lässt Warnungen werfen
wie beim UP Bsp.3 (die Frage des TO).
Warnungen wenn ints statt enums zugewiesen werden oder in einem switch
nicht alle cases oder default auftaucht.
Und im dependency-walk bei lint kann man sich auch warnen lassen, wenn
ein enum per cast einen Wert außerhalb bekommen soll. Natürlich nur in
den Grenzen, die statische Codeanalyse hat.
A. S. schrieb:> Eben. Jeder wie er mag. Wer "Typsicherheit" will, lässt Warnungen werfen> wie beim UP Bsp.3 (die Frage des TO).
Die Warnung dort besagt ja eigentlich, daß der eine case-Block nie
ausgeführt würde, wenn da ein "echter" enum im select benutzt wird, weil
der case-Wert im enum gar nicht definiert ist.
Da ist die Warnung dann schon angebracht.
Oliver
Oliver S. schrieb:> Die Warnung dort besagt ja eigentlich, daß der eine case-Block nie> ausgeführt würde, wenn da ein "echter" enum im select benutzt wird, weil> der case-Wert im enum gar nicht definiert ist.
Was auch gleich direkt zum Problem des Code führt. Ich weiß auch nicht
was es da so lange zu diskutieren gibt:
Es macht keinen Sinn auf Kombinationen von enums zu prüfen, weil ein
enum immer nur einen Wert annehmen kann. Keine Kombination von enum
Werten.
Es handelt sich einfach um ein massives Missverständnis der gesamten
Einrichtung "enum".
Cyblord -. schrieb:> Es macht keinen Sinn auf Kombinationen von enums zu prüfen, weil ein> enum immer nur einen Wert annehmen kann. Keine Kombination von enum> Werten.
Wo genau steht das?
Mombert H. schrieb:> Cyblord -. schrieb:>> Es macht keinen Sinn auf Kombinationen von enums zu prüfen, weil ein>> enum immer nur einen Wert annehmen kann. Keine Kombination von enum>> Werten.> Wo genau steht das?
Das entspricht dem Prinzip von enums. Natürlich kannst du die auf jeden
Wert casten. Aber wenn deine enum Variable einen Wert annimmt, der nicht
im enum definiert ist, bist du außerhalb des Konzepts enum angekommen.
Cyblord -. schrieb:> Es handelt sich einfach um ein massives Missverständnis der gesamten> Einrichtung "enum".
DEINEM Verständnis von enum mag es widersprechen.
Aber letztlich sind enums einfach benamste ganzzahlige Konstanten und
ein eleganterer Ersatz für #define-Orgien.
Zu wissen, was dabei in welchem Bit steht und das zu nutzen ist genauso
legitim oder verwerflich wie bei allen anderen ganzzahligen Werten auch.
In den meisten Fällen wird man mit enum einfach irgendwas abzählen. Das
muß aber nicht immer sein, sonst bräuchte man nicht die Möglichkeit,
beliebige Werte zuzuweisen.
Ob das in diesem Fall dann sinnvoll ist, sei mal dahingestellt. Aber
Aussagen wie "mit enum darf man nur abzählen" kommt man nicht weit
außerhalb vom Einhorngehege.
In C ist es nun mal leider nicht mehr und man muß es nehmen wie es ist.
In C++ kann man echte Typen draus machen; hilft hier aber halt nicht
weiter, wenn man bei C bleiben will.
Cyblord -. schrieb:> Mombert H. schrieb:>> Cyblord -. schrieb:>>> Es macht keinen Sinn auf Kombinationen von enums zu prüfen, weil ein>>> enum immer nur einen Wert annehmen kann. Keine Kombination von enum>>> Werten.>> Wo genau steht das?>> Das entspricht dem Prinzip von enums. Natürlich kannst du die auf jeden> Wert casten. Aber wenn deine enum Variable einen Wert annimmt, der nicht> im enum definiert ist, bist du außerhalb des Konzepts enum angekommen.
Es entspricht nicht deiner Vorstellung von enums, das ist etwas anderes.
Klaus W. schrieb:> Cyblord -. schrieb:>> Es handelt sich einfach um ein massives Missverständnis der gesamten>> Einrichtung "enum".>> DEINEM Verständnis von enum mag es widersprechen.
Ja sicher ich kann hier nur meine Meinung dazu wiedergeben.
> Aber letztlich sind enums einfach benamste ganzzahlige Konstanten und> ein eleganterer Ersatz für #define-Orgien.
Dem würde ich nicht zustimmen. Man kann sie dafür verwenden. Aber man
sollte nicht.
> Aussagen wie "mit enum darf man nur abzählen" kommt man nicht weit> außerhalb vom Einhorngehege.
Wie weit man kommt wenn man meint enum einfach irgendwie zu verwenden
sieht man an obigem Code.
Formal sind nur die Werte zugelassen, die im Enum definiert sind. Das
Switch will auf beiden Seiten den gleichen Typ und warnt daher.
Das == macht implizit eine Konvertierung nach int und warnt daher nicht.
Veit D. schrieb:> Hans-Georg L. schrieb:>>> Was ich mir im C++ Standard wünsche wäre die Abfrage während der>> Compilezeit ob ein Wert im enum enthalten ist oder nicht. Wird aber>> schon diskutiert ...>> Gibts schon. Stichwort enum class ...
Lies nochmal was ich geschrieben habe ... wie Bitte kann ich ein class
enum während der Compilezeit fragen ob ein bestimter Wert darin
enthalten/definiert ist ist oder nicht ? Ich kann eine Fehlermeldung
erzeugen aber keine Abfrage ohne Abbruch.
Peter D. schrieb:> Formal sind nur die Werte zugelassen, die im Enum definiert sind. Das> Switch will auf beiden Seiten den gleichen Typ und warnt daher.> Das == macht implizit eine Konvertierung nach int und warnt daher nicht.
Meinst du mit formal zugelassen den Standard? Wo steht das deiner
Meinung nach? Und switch macht auch in integer promotions.
Mombert H. schrieb:> Meinst du mit formal zugelassen den Standard? Wo steht das deiner> Meinung nach?
Keine Ahnung ob das wirklich im Standard steht. Aber mein Anspruch ist
immer Clean Code und nicht "gerade noch im Standard puh alles gut".
Cyblord -. schrieb:> Mombert H. schrieb:>> Meinst du mit formal zugelassen den Standard? Wo steht das deiner>> Meinung nach?>> Keine Ahnung ob das wirklich im Standard steht. Aber mein Anspruch ist> immer Clean Code und nicht "gerade noch im Standard puh alles gut".
Das kann man auch umdrehen: "Hauptsache es sieht gut aus, egal ob vom
Standard erlaubt" ;-)
Mombert H. schrieb:> Das kann man auch umdrehen: "Hauptsache es sieht gut aus, egal ob vom> Standard erlaubt" ;-)
Kann man. Wäre aber falsch. Der Standard ist die untere Grenze aber ich
würde den Anspruch deutlich höher ansiedeln.
Mombert H. schrieb:> Meinst du mit formal zugelassen den Standard? Wo steht das deiner> Meinung nach?
Eine Stelle konnte ich nicht finden.
Dafür aber ein Beispiel für das Verodern von Enums:
https://www.programiz.com/c-programming/c-enumeration
Da scheint also doch keine Einigkeit zu herschen.
A. S. schrieb:> Hans-Georg L. schrieb:>> Aber da die typedef enums in C keine "echten Datentypen" sind ...>> macht es überhaupt keinen Sinn einen typedef enum als Parameter zu>> benutzen.>> Weil man da lustig alles reinhauen kann was nach int konvertierbar ist.>> Na eben nicht. Darum dreht sich doch der thread. Dass der Compiler da> meckert.>> Also Du bestimmst das in C wie du willst.
ich bestimme nichts ...
wenn ich eine funktion definiere :
void fkt(my_enum value);
und rufe die mit:
fkt(0.5) auf
ist es für mich schon überraschend wenn das ohne Fehler compiliert ...
In C++ benutze ich solche Funktionen um sicher zu stellen das nur im
enum definierte Werte als Parameter zulässig sind und habe
fälschlicherweise angenommen, das wäre in C genau so. Wieder was gelernt
;-)
Peter D. schrieb:> Da scheint also doch keine Einigkeit zu herschen.
Weil man enums grundsätzlich ohne Problem verodern kann. Nur wenn man
das in einem Switch/Case versucht, springt einen das Problem förmlich
an. Davor aber halt nicht.
Der Switch/Case Fall des TE ist auch nochmal was besonderes, weil er
hier ein übergebenes enum explizit auf eine Kombination von enums testen
will. Was absurd falsch ist.
Will ich aber nur irgendeinen Wert auf bestimmte Flags testen, und diese
Flags sind zufällig enums, geht das ohne Verrenkungen. Auch wenn es
nicht so schön ist. Es versursacht aber kein grundlegendes Problem.
Peter D. schrieb:> Mombert H. schrieb:>> Meinst du mit formal zugelassen den Standard? Wo steht das deiner>> Meinung nach?>> Eine Stelle konnte ich nicht finden.> Dafür aber ein Beispiel für das Verodern von Enums:> https://www.programiz.com/c-programming/c-enumeration>> Da scheint also doch keine Einigkeit zu herschen.
Wieso besteht da keine Einigkeit?
Wieso besteht hier keine Einigkeit?
Anscheinend treffen hier zwei grundsätzlich unvereinbare Standpunkte
aufeinander.
Die einen meinen: Im C Standard ist der Missbrauch von enums als
Bitfelder nicht vorgesehen. Deswegen dürfen wir enums auch nicht als
Bitfelder benutzen.
Die anderen meinen: Enums als Bitfelder missbrauchen ist immer noch die
beste aller Lösungen. Auch wenn der automatische enum nach int cast bei
ein paar Konstruktionen nicht funktioniert.
P.S. ich bin der Ansicht, das eigentliche Problem ist - wenn wir ein
paar Libraries einbinden, bekommen wir in einem Programm alle Varianten,
die in den 40 Jahren mal modern waren. Müssen zwischen #define, enum,
struct int:1, usw. hin und her konvertieren.