char[] to enum mithilfe des Präprozessors



  • Hallo zusammen,

    ich kodiere eine Liste von Topics intern als enum. Ein Topic ist zunächst nichts anderes als ein String. Im folgenden Beispiel verwende ich drei Topics, nämlich TOPIC_1, TOPIC_2, TOPIC_3. Alle Topics sind zur Kompilierzeit bekannt:

    #define FOREACH_MESSAGE_TYPE(C) C(TOPIC_1) C(TOPIC_2) C(TOPIC_3)
    #define GENERATE_ENUM(x) x,
    
    enum message_type { FOREACH_MESSAGE_TYPE(GENERATE_ENUM) };
    
    
    int main() {
    
    	enum message_type current_topic = TOPIC_2;
    	printf("%d\n", current_topic);
    	return 0;
    }
    

    Nun möchte ich die TOPICs am liebsten in einer externen Datei verwalten, sodass man diese einfach anpassen kann. Besteht die Möglichkeit, mithilfe des Präprozessors, das enum message_type anhand solch einer Datei zu generieren?

    Bis jetzt wandelt mir ein kleines Script einfach den Dateiinhalt in entsprechenden C-Code um, jedoch frage ich mich, ob es auch schöner (sprich ohne zusätzliches Script) geht.

    Über Anregungen wäre ich dankbar.

    Viele Grüße



  • Ich würde bei einem Script bleiben, da die Arbeit mit der generierten Datei mit "normaler" Syntax den meisten Leute wesentlich einfacher fallen wird.



  • Wenn in der externen Datei die Werte einfach auch mit Komma separiert sind, dann würde es einfach so funktionieren:

    enum message_type
    {
      #include "message_types.txt"
    };
    


  • @freakC sagte in char[] to enum mithilfe des Präprozessors:

    #define FOREACH_MESSAGE_TYPE(C) C(TOPIC_1) C(TOPIC_2) C(TOPIC_3)
    

    Besteht die Möglichkeit, mithilfe des Präprozessors, das enum message_type anhand solch einer Datei zu generieren?

    Du kannst das #define FOREACH_MESSAGE_TYPE in ein eigenes Header-File packen. Damit es etwas übersichtlicher wird kannst du es mit Zeilenumbrüchen formatieren:

    #define FOREACH_MESSAGE_TYPE(C) \
    C(TOPIC_1) \
    C(TOPIC_2) \
    C(TOPIC_3) \
    // end FOREACH_MESSAGE_TYPE
    

    Dabei musst du nur aufpassen dass kein weiteres Zeichen nach dem \ mehr kommt - nichtmal ein Leerzeichen.



  • @hustbaer: Die beiden #define-Zeilen sind doch unsinnig. Warum dann nicht direkt TOPIC_1, TOPIC_2, TOPIC_3 in den enum-Body schreiben?



  • @Th69
    Das ist ein X-Makro (bzw. eine leicht abgewandelte Form davon).
    Die verwendet man normalerweise wenn man die Liste mehrfach braucht.
    z.B. um automatisch eine "to-string" oder "from-string" Funktion für den enum zu implementieren.

    #define FOREACH_FOO(X) X(TOPIC_1) X(TOPIC_2) X(TOPIC_3)
    
    #define GENERATE_ENUM(name) name,
    
    enum Foo {
        FOREACH_FOO(GENERATE_ENUM)
    };
    
    #define GENERATE_TO_STRING(name) case name: return #name;
    
    char const* fooToString(Foo f) {
        switch (f) {
            FOREACH_FOO(GENERATE_TO_STRING)
        }
    }
    
    #define GENERATE_FROM_STRING(name) if (strcmp(s, #name) == 0) return name;
    
    Foo fooFromString(char const* s) {
        FOREACH_FOO(GENERATE_FROM_STRING)
        throw std::invalid_argument("meh");
    }
    
    // ...
    


  • Okay, danke für eure Hinweise.

    Und ja, ich verwende die Makros vor allem für die Rückübersetzung des Enums in einen String.

    Viele Grüße


Anmelden zum Antworten