Ich dachte bisher das enum eine Art Aufzählung sei
z.B. rot, grün, blau.
1
typedefenum
2
{
3
ETH_LINK_ST_DOWN=0x0
4
ETH_LINK_ST_UP=0x1
5
ETH_LINK_ST_LP_NEG_UNABLE=0x2
6
ETH_LINK_ST_REMOTE_FAULT=0x4
7
ETH_LINK_ST_LP_NEG_UNABLE....
8
ETH_LINK_ST_PDF....
9
ETH_LINK_ST_LP_PAUSE....
10
ETH_LINK_ST_LP_ASM_DIR
11
ETH_LINK_ST_NEG_TMO
12
ETH_LINK_ST_NEG_FATAL_ERR
13
}eEthLinkStat;(linkStat)
Ich dachte bisher auch das z.B. linkStat nur einen wert haben kann.
z.B. linkStat = ETH_LINK_ST_UP
oder
linkStat = ETH_LINK_ST_DOWN
Nur scheinbar greifen die jungs da auf einzelne Bits zu.
Wird hier linkStat jedesmal überschrieben? nur da wäre die oder
verknüpfung mit |= so ziemlich fuern arsch.
Oder werden hier tatsächlich nur einzelne Bits gesetzt?
Scheinbar haben die das bei der deklaration von linkStat genau so
gewollt da die jedesmal genau ein Bit festgelegt haben
ETH_LINK_ST_UP hat den Wert 0x1 und nicht 0x2.
Per Definition hat der erste Eintrag den Wert 0 im Enum. Hex, dez oder
bin ist ja zuerstmal egal. Eintrag zwei hat dann den Wert 1, Eintrag
drei den Wert 2 usw.....
Du hast recht in linkStat ist nur ein Wert gespeichert, da es ja auch
nur EINE Variable ist und kein Array. Und den Rest kannst du dir doch
ausrechnen. 0x2 verodert mit 0x4 schreibst du einfach in binär um und
tust die ganzen 1er und 0er verodern. Das Ergebnis rechnest du in Hex
zurück und schon siehst du welchen Wert aus dem Enum in linkStat
enthalten ist
Nun ...
Wenn Du den Enum "in Ruhe lässt", dann zählt er in der Tat einfach hoch
1
typedef enum
2
{
3
ETH_LINK_ST_DOWN,
4
ETH_LINK_ST_UP,
5
ETH_LINK_ST_LP_NEG_UNABLE,
6
ETH_LINK_ST_REMOTE_FAULT
7
....
dann wäre
ETH_LINK_ST_DOWN --> 0
ETH_LINK_ST_UP --> 1
ETH_LINK_ST_LP_NEG_UNABLE --> 2
ETH_LINK_ST_REMOTE_FAULT --> 3
.......
Nun haben aber die Jungs immer genau so einen Wert zugewiesen,
so dass ein Bit gesetzt wird.
ok, nun gut, mal zum verständnis, wie unterscheidet sich eine
union/structure von enum?
1
typedefunion{
2
struct{
3
unsignedPROT_SEL:5;
4
unsignedBASE10T:1;
5
unsignedBASE10T_FDX:1;
6
unsignedBASE100TX:1;
7
unsignedBASE100TX_FDX:1;
8
unsignedBASE100T4:1;
9
unsignedPAUSE:1;// NOTE: the PAUSE fields coding for SMSC is reversed!
10
unsignedASM_DIR:1;// typo in the data sheet?
11
unsigned:1;
12
unsignedREM_FAULT:1;
13
unsigned:1;
14
unsignedNP_ABLE:1;
15
};
16
struct{
17
unsignedshortw:16;
18
};
19
}
ok mal davon abgesehen das union genommen wird um den Speicherbereich zu
Teilen geht es mir nur um die struct selbst. hier wird wieder auf
einzelne Bits zugegriffen. Warum wählte der Programmierer aber in diesem
Fall eine structure und nicht eine enumeration?
David Mueller schrieb:> Ich dachte bisher das enum eine Art Aufzählung sei>> z.B. rot, grün, blau.
Jain.
Tatsächlich ist eine enum nur eine glorifizierte Variante, wie man einen
Integer schreiben kann.
Nichts und niemand hindert dich daran
linkStat = 5;
zu schreiben.
> Wird hier linkStat jedesmal überschrieben? nur da wäre die oder> verknüpfung mit |= so ziemlich fuern arsch.
Achtung!
Das Geheimnis liegt darin, dass du den einzelnen Aufzählngswerten in
einem enum selbst tatsächliche Integer Werte verpassen kannst
In
enum farbe
{
rot,
gruen,
blau
};
sind die Integer Werte für rot, grün und blau tatsächlich 0, 1, 2
Was allerdings niemanden hindert
1
enumfarbecolor=blau|gruen;
zu schreiben. Es werden dann eben die Bitmuster miteinander verodert,
genauso wie es auch bei einem unsigned int der Fall wäre. 0x01 | 0x02
ergibt 0x03. Es gibt keinen Aufzählungswert im enum, der 0x03 wäre. Aber
das hindert niemanden daran, diese 0x03 an color zuzuweisen. Das Problem
ist, dass du im Nachhinein nicht mehr identifizieren kannst, ob die 0x03
sich jetzt aus einer Kombination aus rot+grün+blau zusammen gesetzt hat,
oder ob es nur grün und blau war. Und bei mehr Werten und mehr
Kombinationen wirdsd noch uneindeutiger.
Aber!
Du kannst auch dafür sorgen, dass du rot, grün und blau andere Integer
Werte gibst.
1
enumfarbe
2
{
3
rot=0x01,
4
gruen=0x02,
5
blau=0x04
6
};
und jetzt kannst du die, genauso wie bei Integern einfach zusammenodern.
enum werden in C generell überschätzt. Das ganze Konzept ist (*) nur
halbherzig durchgezogen. Im Grunde ist ein enum nichts anderes als ein
nicht vom Präprozessor abhängiges
1
#define ROT 0x01
2
#define GRUEN 0x02
3
#define BLAU 0x04
Mehr steckt da nicht wirklich dahinter. Enums haben ihren Zweck, weil
man in einer Argumentliste
1
voidSet(enumfarbecol)
dann dokumentiert hat, welche Werte hier erwartet werden, nämlich die
die im enum enthalten sind. Aber mehr ist das nicht. Niemand hindert
dich daran, diese Funktion mit einem Wert von 78 aufzurufen.
(*) Im Vergleich zu anderen Sprachen wie zb Pascal, die ja auch über
Mengen-Datentypen verfügen.
David Mueller schrieb:> ok, nun gut, mal zum verständnis, wie unterscheidet sich eine> union/structure von enum?
komplett.
völlig andere Baustelle
mit einem enum beschreibst du eine Menge von 'möglichen' Werten. Zum
Beispiel die Kartenfarben oder möglichen Kartenwerte von Spielkarten.
Das hat noch nichts mit Speicher oder Speicherform oder
Speicheranforderung zu tun.
In
variable = wert
Ist die 'struct' ein Mittel um die Eigenschaften von 'variable' zu
beschreiben. Ein enum hingegen beschreibt die Eigenschaften von 'wert'.
Aber wirklich Sinn hat so eine Aktion nicht. Der beste Effekt, den
enums sonst noch haben ist, dass Debugger die Werte dann symbolisch
darstellen können. Wenn man nun aber mehrere Werte verODERt, dann
entstehen daraus Werte, die keinen Eintrag im enum-Typ haben, dann
kann man auch gleich "int" schreiben.
Wenn man das Zeug verodern will, sollte man Bitfelder nehmen.
Danke für die ganzen Antworten!
Jörg Wunsch schrieb:> Wenn man nun aber mehrere Werte verODERt, dann> entstehen daraus Werte, die keinen Eintrag im enum-Typ haben, dann> kann man auch gleich "int" schreiben.
das war mein Problem warum ich es nicht verstand.
MPLABX schreibt dann in der variablen liste beim debuggen nur noch
"enumeration?" aus weil er es ebend nicht zuordnen kann.
Christian schrieb:> Ich setze Enums gerne ein um States zu definieren
Dafür ist es ja auch sinnvoll.
Sowie da aber irgendwie ein "|"-Operator ins Spiel kommt, hat die
Sache mit einem enum keinen Sinn mehr. Dann kann man die
Komponenten-Konstanten auch gleich mit #define vereinbaren. Klar,
vielleicht gibt es irgendwo Codierungs-Regeln, die besagen: „#define
ist übel, benutze enum stattdessen“, aber das sture Befolgen dieser
Regel bringt an dieser Stelle keinen Gewinn irgendeiner Art. Ein
Bitfield wäre dann u. U. die bessere Lösung.
Jörg Wunsch schrieb:> Dann kann man die> Komponenten-Konstanten auch gleich mit #define vereinbaren. Klar,> vielleicht gibt es irgendwo Codierungs-Regeln, die besagen: „#define> ist übel, benutze enum stattdessen“,
enums sind Teil dessen, was der Compiler sieht, #defines nicht. Das
heißt auch, dass ein Debugger über enums und dessen Symbole Bescheid
weiß, während #defines einfach nur Literale einsetzen und die
Information über die Namen verloren geht.
Kann es sein, dass aktuelle Versionen von gcc/gdb mittlerweile auch
Präprozessor-Symbole irgendwie in den Debugging-Informationen eintragen?
Habe ich gerade nicht ausprobiert.
Andreas B. schrieb:> enums sind Teil dessen, was der Compiler sieht, #defines nicht. Das> heißt auch, dass ein Debugger über enums und dessen Symbole Bescheid> weiß, während #defines einfach nur Literale einsetzen und die> Information über die Namen verloren geht.>> Kann es sein, dass aktuelle Versionen von gcc/gdb mittlerweile auch> Präprozessor-Symbole irgendwie in den Debugging-Informationen eintragen?
Ja, spätestens seit DWARF-3.
Andreas B. schrieb:> Das heißt auch, dass ein Debugger über enums und dessen Symbole Bescheid> weiß
Das hilft aber nicht, wenn du mit diesen enum-Werten etwas anderes
als eine reine Zuweisung / einen Test machst. Insbesondere also,
wenn du mit den Dingern rechnest (Bitoperationen hier im Beispiel),
dann kommen da eben u. U. Werte raus, die gar kein enum-Äquivalent
besitzen.
Die einzige Rechnung, die Sinn hat, wäre ein Inkrement oder ein
Dekrement bis zum Ende bzw. Anfang, vorausgesetzt, dass die einzelnen
enum-Werte lückenlos sind (wie es bspw. bei einer Aufzählung ohne
explizite Wertzuweisung passiert).
Johann L. schrieb:> Ja, spätestens seit DWARF-3.
Schon bei stabs so gewesen.
Jörg Wunsch schrieb:> Johann L. schrieb:>> Ja, spätestens seit DWARF-3.>> Schon bei stabs so gewesen.
Echt? Ich hab mal Probeweise die gleiche C-Quelle einmal mit stabs und
einmal mit dwarf-3 compiliert. In der dwarf-3 sind deutlich mehr Infos
und die Werte aller Makros; auch der built-in Makros des Compilers. Bei
stans fehlen diese, und auch das
#define ABCD 0
findet sich nicht, welches im dwarf-3 erscheint als
.LASF1638:
.string "ABCD 0"
Michael Reinelt schrieb:> Für mich ein großer Vorteil von enum
Wir brauchen jetzt hier nicht allgemein über Vorteile von enums zu
philosophieren. Davon abgesehen, dass das in C (leider) trotzdem
nur ein Alias für “int” ist, sind diese klar. Hier ging es ganz
konkret um einen Missbrauch von enums für Dinge, für die er weder
konzipiert worden ist noch in irgendeiner Weise Sinn hat.
Wenn du jetzt nicht weißt, was ich damit meine, dann lies dir bitte
den Rest des Threads erstmal durch.
Johann L. schrieb:>>> Ja, spätestens seit DWARF-3.>> Schon bei stabs so gewesen.>> Echt? Ich hab mal Probeweise die gleiche C-Quelle einmal mit stabs und> einmal mit dwarf-3 compiliert. In der dwarf-3 sind deutlich mehr Infos> und die Werte aller Makros
Makros sind ja auch eine andere Baustelle. Aber enum-Elemente gibt's
wirklich schon lange, auch in den Debuginfos. Mir ist sogar so, als
ob diese in den native COFF debug infos drin gewesen wären. Die
haben eigentlich schon seit 25 Jahren keine Relevanz mehr (weil sie
bereits C89s Erweiterungen wie Prototypen nicht abbilden können),
die sind aber beim AVR durch AVR Studio 4 seinerzeit nochmal
aufgewärmt worden, bevor das Studio endlich ELF und DWARF verstanden
hat. (Die Unixe haben zwar noch ein Weilchen COFF benutzt damals,
aber als Debuginfo dann bereits stabs da reingepackt, denn das ging
auch mit COFF schon.)
Jörg Wunsch schrieb:> Johann L. schrieb:>>>> Ja, spätestens seit DWARF-3.>>> Schon bei stabs so gewesen.>>>> Echt? Ich hab mal Probeweise die gleiche C-Quelle einmal mit stabs und>> einmal mit dwarf-3 compiliert. In der dwarf-3 sind deutlich mehr Infos>> und die Werte aller Makros>> Makros sind ja auch eine andere Baustelle. Aber enum-Elemente gibt's> wirklich schon lange, auch in den Debuginfos.
Ok, meine Aussage bezug sich auf "Präprozessor-Symbole" wo ich davon
ausging, daß Makros damit gemeint sind:
Andreas B. schrieb:> Kann es sein, dass aktuelle Versionen von gcc/gdb mittlerweile auch> Präprozessor-Symbole irgendwie in den Debugging-Informationen eintragen?> Habe ich gerade nicht ausprobiert.
Johann L. schrieb:> Ok, meine Aussage bezug sich auf "Präprozessor-Symbole"
Mea culpa, diesmal hatte ich nicht richtig gelesen. Ja, die gibt's
natürlich erst in aktuellem DWARF. Wobei gegenüber dem enum
natürlich für den Debugger trotzdem nicht die Möglichkeit besteht,
ein Objekt vom Typ "int" dann automatisch mit seinem Makrowert
darzustellen, denn er dürfte keine Ahnung haben, ob das Objekt nun
ausschließlich durch die Verwendung mit Makros bearbeitet worden ist
oder nicht. Selbst wenn, wird es oft genug mehrere Makros für den
gleichen Wert geben (NULL oder NO_VALUE zum Beispiel), da könnte
der Debugger auch nicht entscheiden, welchen Makro er benutzen soll.
Der einzige Wert, den ich da sehe wäre, dass man im Debugger dann
schreiben kann:
1
(gdb) set myvar = MYVALUE1
weil er jetzt eine Kennung über den Wert von Makro MYVALUE1 hat (aber
das allein ist natürlich schon mal nett gegenüber früher).