Warum können zwei verschiedene enum-Enumerationskonstanten denselben ganzzahligen Wert haben?

Lesezeit: 4 Minuten

Benutzeravatar von Xu Hong
Xu Hong

Ich weiß das, wenn ich einen Enum-Wochentag wie folgt definiert habe:

enum weekday {
    MON,
    TUE,
    WED,
    THU,
    FRI,
};

Dann wäre MON intern standardmäßig gleich 0 und TUE gleich 1, WED gleich 2 …

Aber wenn ich es so definiere:

enum weekday {
    MON,
    TUE = 0,
    WED,
    THU,
    FRI,
};

Dann beides MON und TUE würde den Wert 0 bekommen.

Wie würde ein System MON und TUE intern unterscheiden? Ich meine, wenn ich so etwas deklariere:

enum weekday today = 0;

Dann ist heute MON oder TUE? Oder, philosophisch gesprochen, beides?

  • @quasiverse – ich habe, MON und TUE sind beide 0. +1, das wusste ich nicht.

    – Kiril Kirow

    10. Juli 2012 um 11:44 Uhr

  • Das enum Konstanten sind ints. Sie sind nur hoffentlich aussagekräftige Namen für einige Integer-Konstanten. Was ist also der Deal, wenn Sie sich mit zwei Namen auf dasselbe beziehen können?

    – Daniel Fischer

    10. Juli 2012 um 11:47 Uhr

  • Es gibt keine Philosophie, nur Logik: today == MON == TUE == 0.

    – Aschera

    10. Juli 2012 um 11:54 Uhr

  • Eine „Ist es legal“-Version: stackoverflow.com/questions/5561142/duplicate-enum-values-in-c/…

    – Ciro Santilli OurBigBook.com

    18. Juni 2015 um 13:21 Uhr

  • Es ist im Grunde eine Alternative zu constexpr für Systeme, die constexpr nicht unterstützen. außer dass die constexprints gekoppelt sind

    – Dmitri

    12. November 2017 um 22:19 Uhr

Benutzeravatar von Steve Jessop
Steve Jessop

C-Enumerationen sind „wirklich“ Ganzzahlen – nicht nur, weil sie zufällig so implementiert sind, sondern weil es der Standard ist definiert Enum-Typen haben ganzzahlige Werte. Also der Wert von today ist “wirklich” 0. Alles, was passiert ist, ist, dass Sie zwei verschiedene Namen für den Wert 0 erstellt haben.

Ich nehme an, dass die Antwort auf “ist heute MO oder DI” “ja” lautet 😉

Die Sprache hält Sie nicht auf, denn gelegentlich ist es nützlich, dass eine Aufzählung mehrere Namen für denselben Wert hat. Zum Beispiel:

enum compression_method {
    COMP_NONE = 0,
    COMP_LOW = 1,
    COMP_HIGH = 2,
    COMP_BEST = 2,
    COMP_FASTEST = 0,
};

  • Hahahaha, +1 für I suppose then that the answer to "is today MON or TUE" is "yes" ;-) 😀

    – Kiril Kirow

    10. Juli 2012 um 11:48 Uhr

  • Eine bessere Lösung ist hier zu haben COMP_FASTEST = COMP_NONEmeiner Meinung nach.

    – mmtauqir

    17. Juni 2014 um 2:46 Uhr

  • selbst wenn MON und DI verschieden wären, kann die Antwort auf „ist heute MON oder DI“ immer noch „ja“ lauten, wenn der Computer eine „ODER“-Verknüpfung vornimmt. Ich glaube, Sie haben nach „ist heute MO und DI“ gesucht.

    – Ofek Gila

    10. August 2018 um 16:48 Uhr

Ciro Santilli Benutzeravatar von OurBigBook.com
Ciro Santilli OurBigBook.com

Warum können zwei verschiedene Aufzählungskonstanten denselben ganzzahligen Wert haben?

Weil es ausdrücklich von der erlaubt ist N1265 C99 Standardentwurf bei 6.7.2.2/3 “Aufzählungsbezeichner”:

Die Verwendung von Enumeratoren mit = kann Aufzählungskonstanten mit Werten erzeugen, die andere Werte in derselben Aufzählung duplizieren.

Wie würde ein System MON und TUE intern unterscheiden?

Ich denke, es ist unmöglich, weil es sich um Kompilierzeitkonstanten handelt (6.6/6 “Konstante Ausdrücke”). Als Konsequenz sie:

  • können nicht geändert werden, um sie nach der Kompilierung zu unterscheiden

  • haben keine Adresse, um sie zu unterscheiden: Speicherort des Aufzählungswerts in C

    Kompilierzeitkonstanten benötigen keine Adresse, da Adressen für Dinge nutzlos sind, die Sie nicht ändern können.

GCC ersetzt einfach die Verwendung von Aufzählungsmitgliedern durch unmittelbare Werte in der Assemblierung zur Kompilierzeit. In Betracht ziehen:

#include <stdio.h>

enum E {
    E0 = 0x1234,
    E1 = 0x1234
};
int i = 0x5678;

int main() {
    printf("%d\n", E0);
    printf("%d\n", E1);
    printf("%d\n", i);
    return 0;
}

Kompilieren und dekompilieren mit GCC 4.8 x86_64:

gcc -c -g -O0 -std=c89 main.c
objdump -Sr main.o

Die Ausgabe enthält:

    printf("%d\n", E0);
   4:       be 34 12 00 00          mov    $0x1234,%esi
  ...
    printf("%d\n", E1);
  18:       be 34 12 00 00          mov    $0x1234,%esi
  ...
    printf("%d\n", i);
  2c:       8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 32 <main+0x32>
                    2e: R_X86_64_PC32       i-0x4
  32:       89 c6                   mov    %eax,%esi

Also wir sehen das:

  • Die Aufzählungsmitglieder werden als Direktwerte verwendet $0x1234daher ist es unmöglich zu wissen, woher sie kamen
  • Die Variable i kommt aber aus der erinnerung 0x0(%rip) (zu verschieben), sodass zwei Variablen anhand der Adresse unterschieden werden können

Nur um andere Antworten zu ergänzen, gebe ich Ihnen ein praktisches Beispiel dafür, wie Sie denselben Wert für verschiedene Aufzählungen für einen bestimmten Wert verwenden enum ist weithin nützlich:

enum slots_t {
    SLOT_FIRST = 0,
    SLOT_LEFTARM = SLOT_FIRST,
    SLOT_RIGHTARM = 1,
    SLOT_TORSO = 2,
    SLOT_LEFTLEG = 3,
    SLOT_RIGHTLEG = 4,
    SLOT_LAST = SLOT_RIGHTLEG
};

Dann können Sie in Ihrem Code tun:

for (int i = SLOT_FIRST; i <= SLOT_LAST; ++i) { }

  • Ich würde lieber SLOT_MAX = 4 statt SLOTLAST = SLOT_RIGHTLEG definieren, falls ein anderer Programmierer auf die tolle Idee kommt, die Werte für SLOT_LEFTLEG und SLOT_RIGHTLEG auszutauschen

    – Grenix

    15. Dezember 2017 um 13:53 Uhr


  • Normalerweise verwende ich SLOT_MAX mit nicht erzwungenem Wert, damit der Compiler last + 1 zuweist. Dadurch kann ein Array definiert werden, z. bool slot_valid[SLOT_MAX]; Oder Schleifen mit traditionelleren i < SLOT_MAX.

    – mguin

    11. Januar um 18:54 Uhr

Es ist so philosophisch (oder nicht) wie

#define ZILCH 0
#define NADA  0

Es gibt viele Anwendungen, bei denen es sinnvoll ist, dass unterschiedliche Namen dieselbe Nummer ergeben.

Zur Wertzuweisung wird der Name der Aufzählungskonstante verwendet und nicht der eigentliche Wert selbst. Wenn Sie dem heutigen Tag den Wert 0 zuweisen, ist der Ausgabewert 0. Und ja, sowohl MON als auch TUE haben den Wert 0 und den verbleibenden wird der Wert WED = 1 THU = 2 zugewiesen und so weiter.

1412020cookie-checkWarum können zwei verschiedene enum-Enumerationskonstanten denselben ganzzahligen Wert haben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy