Gibt Text statt Wert aus C enum aus

Lesezeit: 8 Minuten

Benutzeravatar von avi
avi

int main()
{

  enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

  Days TheDay;

  int j = 0;

  printf("Please enter the day of the week (0 to 6)\n");

  scanf("%d",&j);

  TheDay = Days(j);

  //how to PRINT THE VALUES stored in TheDay

  printf("%s",TheDay);  //   isnt working

  return 0;
}

  • Ihre erwartete Ausgabe soll die Zeichenfolge “Sonntag” usw. drucken?

    – Galaktischer Cowboy

    2. Juli 2010 um 18:45 Uhr

Aufzählungen in C sind Zahlen, die in Ihrem Code praktische Namen haben. Sie sind keine Strings, und die ihnen im Quellcode zugewiesenen Namen werden nicht in Ihr Programm kompiliert, sodass sie zur Laufzeit nicht zugänglich sind.

Die einzige Möglichkeit, das zu bekommen, was Sie wollen, besteht darin, selbst eine Funktion zu schreiben, die den Enumerationswert in einen String übersetzt. Beispiel (vorausgesetzt, Sie verschieben die Erklärung von enum Days außerhalb main):

const char* getDayName(enum Days day) 
{
   switch (day) 
   {
      case Sunday: return "Sunday";
      case Monday: return "Monday";
      /* etc... */
   }
}

/* Then, later in main: */
printf("%s", getDayName(TheDay));

Alternativ könnten Sie ein Array als Karte verwenden, z

const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };

/* ... */

printf("%s", dayNames[TheDay]);

Aber hier würde man wohl zuordnen wollen Sunday = 0 in der Enumeration, um sicher zu sein … Ich bin mir nicht sicher, ob der C-Standard verlangt, dass Compiler Enumerationen bei 0 beginnen, obwohl die meisten dies tun (ich bin sicher, dass jemand kommentieren wird, um dies zu bestätigen oder zu verneinen).

  • Oh, du bist mir bei der Array-Lösung zuvorgekommen. 😛 Aber ja, Aufzählungen beginnen immer bei 0, es sei denn, Sie geben einen anderen Wert an.

    – Casablanca

    2. Juli 2010 um 18:51 Uhr

  • Wenn ich mich darauf verlassen würde, die Aufzählungen als Indizes zu verwenden, würde ich es tatsächlich vorziehen, jede explizit zu nummerieren. Laut Standards unnötig, aber als Gruppe waren Compiler meiner Erfahrung nach nicht gerade die besten darin, Standards zu befolgen.

    – jdmichal

    2. Juli 2010 um 18:51 Uhr

  • Der C-Standard sagt: „Wenn der erste Enumerator kein = hat, ist der Wert seiner Enumerationskonstante 0“. Aber es schadet nichts, es explizit zu haben.

    – Michael Burr

    2. Juli 2010 um 18:52 Uhr

  • Vergessen Sie nicht, dass Sie das mit C99 tun können const char* dayNames[] = {[Sunday] = "Sunday", [Monday] = "Monday", [Tuesday] = "Tuesday", /* ... etc ... */ };. Sie wissen, falls die Wochentage neu geordnet werden oder Sie entscheiden, dass Montag der erste Tag der Woche ist.

    – Tim Schäfer

    2. Juli 2010 um 20:13 Uhr


  • @ user3467349 Das (Präprozessor-Stringifizierung) wandelt nur das Symbol nach dem # in eine Zeichenfolge um. Also, ja, #Montag würde zu “Montag” werden, aber Days TheDay = Monday; printf("%s", #TheDay); würde “TheDay” drucken.

    – Tyler McHenry

    7. Juni 2015 um 20:31 Uhr

Ich benutze so etwas:

in einer Datei “EnumToString.h”:

#undef DECL_ENUM_ELEMENT
#undef DECL_ENUM_ELEMENT_VAL
#undef DECL_ENUM_ELEMENT_STR
#undef DECL_ENUM_ELEMENT_VAL_STR
#undef BEGIN_ENUM
#undef END_ENUM

#ifndef GENERATE_ENUM_STRINGS
    #define DECL_ENUM_ELEMENT( element ) element,
    #define DECL_ENUM_ELEMENT_VAL( element, value ) element = value,
    #define DECL_ENUM_ELEMENT_STR( element, descr ) DECL_ENUM_ELEMENT( element )
    #define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_VAL( element, value )
    #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
    #define END_ENUM( ENUM_NAME ) ENUM_NAME; \
            const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
    #define BEGIN_ENUM( ENUM_NAME) const char * GetString##ENUM_NAME( enum tag##ENUM_NAME index ) {\
        switch( index ) { 
    #define DECL_ENUM_ELEMENT( element ) case element: return #element; break;
    #define DECL_ENUM_ELEMENT_VAL( element, value ) DECL_ENUM_ELEMENT( element )
    #define DECL_ENUM_ELEMENT_STR( element, descr ) case element: return descr; break;
    #define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_STR( element, descr )

    #define END_ENUM( ENUM_NAME ) default: return "Unknown value"; } } ;

#endif

dann machen Sie in jeder Header-Datei die Enum-Deklaration, Tag enum.h

#include "EnumToString.h"

BEGIN_ENUM(Days)
{
    DECL_ENUM_ELEMENT(Sunday) //will render "Sunday"
    DECL_ENUM_ELEMENT(Monday) //will render "Monday"
    DECL_ENUM_ELEMENT_STR(Tuesday, "Tuesday string") //will render "Tuesday string"
    DECL_ENUM_ELEMENT(Wednesday) //will render "Wednesday"
    DECL_ENUM_ELEMENT_VAL_STR(Thursday, 500, "Thursday string") // will render "Thursday string" and the enum will have 500 as value
    /* ... and so on */
}
END_ENUM(MyEnum)

dann in einer Datei namens EnumToString.c:

#include "enum.h"

#define GENERATE_ENUM_STRINGS  // Start string generation

#include "enum.h"             

#undef GENERATE_ENUM_STRINGS   // Stop string generation

dann in main.c:

int main(int argc, char* argv[])
{
    Days TheDay = Monday;
    printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "1 - Monday"

    TheDay = Thursday;
    printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "500 - Thursday string"

    return 0;
}

Dadurch werden die Zeichenfolgen für alle auf diese Weise deklarierten und in “EnumToString.c” enthaltenen Aufzählungen “automatisch” generiert.

  • Es ist hässlich, es durchzulesen, aber Sie haben keine Datenduplizierung. (Im Gegensatz zu allen anderen.) Ich bin hin- und hergerissen, ob ich das mögen soll.

    – Kim Reece

    2. Juli 2010 um 19:25 Uhr

  • +1 für die unglaublich kreative Lösung ohne Datenduplizierung und wahrscheinlich die beste Wartbarkeit/Flexibilität, aber ja! Ich denke, ich würde immer noch lieber einfach den const char*[] Route.

    – manifestieren

    2. Juli 2010 um 21:00 Uhr

  • Ja, die Wartbarkeit ist genial! Es ist wirklich einfach zu aktualisieren, wenn sich die Wochentage ändern! Übrigens ist dies nicht einmal für Lokalisierungszwecke nützlich, da die Zuordnung zwischen den englischen Zeichenfolgen und den Namen im Programm jetzt durch Ihren Versuch, Duplikate zu vermeiden, fest codiert ist. Zumindest mit den anderen Ansätzen ist es möglich, die Zeichenfolgen zu übersetzen, ohne jedes Vorkommen in den Quelldateien zu ändern.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    3. Juli 2010 um 5:20 Uhr

  • Sie können es wahrscheinlich internationalisieren, indem Sie (mit etwas wie gettext) die return-Anweisungen in ändern return _(#element) und dergleichen.

    – Varga

    5. Juli 2010 um 12:09 Uhr

  • Wenn der C-Präprozessor so nützlich, aber so hässlich ist, ersetze ich ihn normalerweise durch einen einfachen Codegenerator oder einen benutzerdefinierten Präprozessor in einer Skriptsprache. Und tatsächlich habe ich ein Python-Skript, das ich für genau diesen Zweck in mehreren Projekten verwendet habe. Aber ich benutze es heutzutage nicht mehr so ​​oft – für viele Anwendungsfälle können Sie damit davonkommen, nur Strings zu verwenden und sich nicht um die Aufzählungen zu kümmern (und noch mehr in C++ oder ObjC).

    – Abart

    11. Mai 2012 um 0:50 Uhr

Normalerweise mache ich das, indem ich die String-Darstellungen in einem separaten Array in derselben Reihenfolge speichere und dann das Array mit dem Enum-Wert indiziere:

const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"

enums in C funktionieren nicht wirklich so, wie Sie es erwarten. Sie können sie sich wie verherrlichte Konstanten vorstellen (mit ein paar zusätzlichen Vorteilen, die sich darauf beziehen, eine zu sein Sammlung solcher Konstanten) und der Text, den Sie für “Sonntag” geschrieben haben, beim Kompilieren wirklich in eine Zahl aufgelöst wird, wird der Text schließlich verworfen.

Kurz gesagt: Um das zu tun, was Sie wirklich wollen, müssen Sie ein Array der Strings behalten oder eine Funktion erstellen, um den Wert der Aufzählung dem Text zuzuordnen, den Sie drucken möchten.

Aufzählungen in C sind im Grunde syntaktischer Zucker für benannte Listen von automatisch sequenzierten Integerwerten. Das heißt, wenn Sie diesen Code haben:

int main()
{
    enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

    Days TheDay = Monday;
}

Ihr Compiler spuckt tatsächlich Folgendes aus:

int main()
{
    int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}

Daher ist die Ausgabe einer C-Enumeration als String keine für den Compiler sinnvolle Operation. Wenn Sie für Menschen lesbare Zeichenfolgen haben möchten, müssen Sie Funktionen definieren, um Aufzählungen in Zeichenfolgen umzuwandeln.

Hier ist eine sauberere Möglichkeit, dies mit Makros zu tun:

#include <stdio.h>
#include <stdlib.h>

#define DOW(X, S)                                                         \
    X(Sunday) S X(Monday) S X(Tuesday) S X(Wednesday) S X(Thursday) S X(Friday) S X(Saturday)

#define COMMA ,

/* declare the enum */
#define DOW_ENUM(DOW) DOW
enum dow {
    DOW(DOW_ENUM, COMMA)
};

/* create an array of strings with the enum names... */
#define DOW_ARR(DOW ) [DOW] = #DOW
const char * const dow_str[] = {
    DOW(DOW_ARR, COMMA)
};

/* ...or create a switchy function. */
static const char * dowstr(int i)
{
#define DOW_CASE(D) case D: return #D

    switch(i) {
        DOW(DOW_CASE, ;);
    default: return NULL;
    }
}


int main(void)
{
    for(int i = 0; i < 7; i++)
        printf("[%d] = «%s»\n", i, dow_str[i]);
    printf("\n");
    for(int i = 0; i < 7; i++)
        printf("[%d] = «%s»\n", i, dowstr(i));
    return 0;
}

Ich bin mir nicht sicher, ob dies vollständig tragbare S / W-Präprozessoren sind, aber es funktioniert mit gcc.

Das ist übrigens c99, also benutze es c99 strict wenn du es einsteckst (der Online-Compiler) ideone.

Benutzeravatar von fortytwo
zweiundvierzig

Ich weiß, dass ich zu spät zur Party komme, aber wie wäre es damit?

const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ };
printf("%s", dayNames[Sunday]); // prints "Sunday"

Auf diese Weise müssen Sie die nicht manuell aufbewahren enum und die char* Array synchron. Wenn Sie wie ich sind, stehen die Chancen gut, dass Sie das später ändern werden enumund die char* Array gibt ungültige Zeichenfolgen aus. Dies ist möglicherweise keine universell unterstützte Funktion. Aber afaik, die meisten modernen C-Compiler unterstützen diesen designierten Initialisierungsstil.

Sie können mehr über designierte Initialisierer lesen hier.

1421030cookie-checkGibt Text statt Wert aus C enum aus

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

Privacy policy