Enum Wert zur Laufzeit ermitteln



  • Hallo,
    ich bin auf der Suche nach einer Lösung habe aber bisher noch keine gefunden, die sich auch umsetzten lässt.
    Es handelt sich dabei um Dateien die Enumerationen enthalten.
    Diese werden dazu verwendet um Adressen zu speichern.

    Beispiel:

    enum
    {
        SPEICHERADRESSE1 = 0x00000000,
        SPEICHERADRESSE2,
        SPEICHERADRESSE3,
        SPEICHERADRESSE4,
        SPEICHERADRESSE5
    

    Das ganze gibt es natürlich nicht nur für einige wenige sondern für viele Hunderte von Adressen. Es scheidet also eine Hardgecodete Lösung aus.
    Ich habe außerdem eine Datei in der die Namen gespeichert sind.
    Also

    SPEICHERADRESSE1 SPEICHERADRESSE2 SPEICHERADRESSE3 SPEICHERADRESSE4 SPEICHERADRESSE5

    Diese Datei lese ich ein mit:

    symbol_names_file.open("enum_names.txt", ios_base::in);
    if(symbol_names_file == 0) { cout << "Fehler beim einlesen der Datei" << endl; return; }
    for( string enum_name; getline( symbol_names_file, enum_name, symbol_names_file.widen(' ') ); )
    {
     cout << "Gelesen: [" << enum_name << "]" << endl;
     int enum_mnr = 0;
     enum_list.push_back(MSTEnum(enum_name, enum_mnr);
    }
    
    symbol_names_file.close();
    

    Meine Frage ist jetzt, wie kann ich die Strings aus der "enum_names"-Datei in den Wert des Enums übersetzen?
    Damit ich später mit SPEICHERADRESSE1 nach 0x00000000 und von 0x00000000 nach SPEICHERADRRESSE1 konvertieren kann.
    Hat da jemand eine Idee?
    Danke
    Grüßle Oli



  • Zur Laufzeit sind die Namen der enums nicht mehr bekannt.
    Die oft empfohlene Lösung dafür ist die Verwendung einer std:🗺

    #include <map>
    
    typedef std::map<std::string, size_t> Map;
    
    Map map;
    map["SPEICHERADRESSE1"] = 0x00000000;
    map["SPEICHERADRESSE2"] = 0x47114711;
    

    Mittels der Methode find() kannst du dann nach einer speziellen Adresse (z.B. "SPEICHERADRESSE2") suchen.

    Ich frage mich nur, was du mit diesen (absoluten) Speicheradressen anfängst???



  • Danke für die schnelle Antwort.

    Th schrieb:

    Zur Laufzeit sind die Namen der enums nicht mehr bekannt.

    Hm schade eigentlich, das hab ich mir schon fast gedacht. 😞

    Th schrieb:

    Die oft empfohlene Lösung dafür ist die Verwendung einer std:🗺

    #include <map>
    
    typedef std::map<std::string, size_t> Map;
    
    Map map;
    map["SPEICHERADRESSE1"] = 0x00000000;
    map["SPEICHERADRESSE2"] = 0x47114711;
    

    Mittels der Methode find() kannst du dann nach einer speziellen Adresse (z.B. "SPEICHERADRESSE2") suchen.

    Das mit der map ist zwar ne coole Lösung aber funktioniert in meinem Fall leider nicht, da die Dateien mit den Enums leider schon exisitieren und sehr groß sind und ich diese ja irgendwie in die map reinbekommen muss.
    Außerdem sind die Enum-Dateien, Teil von einem System an dem "mein" Programm als Client hängt. Ich möchte also hardcoden vermeiden und das ganze austauschbar gestalten.
    Das läuft aber dann wohl auf einen Parser raus oder?

    Th schrieb:

    Ich frage mich nur, was du mit diesen (absoluten) Speicheradressen anfängst???

    Ich kommuniziere(über einen Socket) mit einem System, das über die absolute Adresse auf seine Daten zugreift. Um es dem Benutzer aber zu erleichten würde ich gerne einen String verwenden und nicht einfach nur eine Zahl.
    Darum diese Umwandlung.



  • Hmm? Naja ... also std::map<MSTEnum, int> data; würde gehen ^^



  • (D)Evil schrieb:

    Hmm? Naja ... also std::map<MSTEnum, int> data; würde gehen ^^

    Wie denn?? Ich steh da dezent auf dem Schlauch 🙂 .



  • Also verstehe ich dich richtig? Du hast eine Datei, in der schon die enums aufgelistet sind (als Header-Datei) und du willst jetzt auf die Enum-Namen zur Laufzeit zugreifen.

    Dann wäre es wohl wirklich das einfachste, dafür einen Parser zu verwenden, der die Datei liest und diese Werte dann in die von mir beschriebene Map schreibt.
    Wenn diese Datei konstant ist, dann kanst du sie ja vielleicht noch so formatieren, daß der Parser simpel zu schreiben ist:

    ifstream iff("enums.h");
    if(!iff) return;
    
    std::string sEnum;
    size_t nEnum;
    char c;
    
    while(!iff.eof())
    {
      iff << sEnum << c;
      if(c != '=')
        break; // Error: kein Gleichheitszeichen
    
      iff << hex << nEnum << c;
      if(c != ',')
        break; // Error: Komma fehlt
    
      map[sEnum] = nEnum;
    }
    

    Zu beachten dabei ist, daß ich davon ausgehe, daß vor dem Gleichheitszeichen immer ein Leerzeichen ist (ansonsten mußt du den Parser anpassen):

    SPEICHERADRESSE1 = 0x00000000,
    

    Wenn du auch enums ohne Zuweisung haben willst (wie z.B. "SPEICHERADRESSE2,") dann mußt du einfach den vorherigen 'nEnum' Wert um eins addieren (bzw. zu Beginn am besten mit 0 initialisieren) und dementsprechend den Parser anpassen.

    Anschließend befinden sich die Daten in der Map (am besten als Klassenvariable deklariert) und du kannst dann damit nach einzelnen Namen mit find() suchen (O(log N)).
    Bei einem Array (oder std::vector) hättest du ja ein lineares Suchverhalten (O(N)), daher die Empfehlung für das Array (insebsondere bei mehreren Hundert oder mehr Einträgen).



  • Th schrieb:

    Also verstehe ich dich richtig? Du hast eine Datei, in der schon die enums aufgelistet sind (als Header-Datei) und du willst jetzt auf die Enum-Namen zur Laufzeit zugreifen.

    Jo du verstehst mich richtig.

    Th schrieb:

    Dann wäre es wohl wirklich das einfachste, dafür einen Parser zu verwenden, der die Datei liest und diese Werte dann in die von mir beschriebene Map schreibt.
    Wenn diese Datei konstant ist, dann kanst du sie ja vielleicht noch so formatieren, daß der Parser simpel zu schreiben ist:

    ifstream iff("enums.h");
    if(!iff) return;
    
    std::string sEnum;
    size_t nEnum;
    char c;
    
    while(!iff.eof())
    {
      iff << sEnum << c;
      if(c != '=')
        break; // Error: kein Gleichheitszeichen
    
      iff << hex << nEnum << c;
      if(c != ',')
        break; // Error: Komma fehlt
    
      map[sEnum] = nEnum;
    }
    

    Zu beachten dabei ist, daß ich davon ausgehe, daß vor dem Gleichheitszeichen immer ein Leerzeichen ist (ansonsten mußt du den Parser anpassen):

    SPEICHERADRESSE1 = 0x00000000,
    

    Wenn du auch enums ohne Zuweisung haben willst (wie z.B. "SPEICHERADRESSE2,") dann mußt du einfach den vorherigen 'nEnum' Wert um eins addieren (bzw. zu Beginn am besten mit 0 initialisieren) und dementsprechend den Parser anpassen.

    Thx für den Parser, aber ganz so einfach ist es leider nicht. Die Dateien sind von dem System auf das ich zugreife und sollen nicht verändert werden. Damit scheidet das schon mal aus. Es handelt sich hierbei auch um 700kB Daten und das ist nicht so einfach zu händeln. Ich würde das gerne komplett automatisieren.
    Die Enums sind nicht einfach linear durchnummeriert sondern es gibt Sprünge und
    in den entsprechenden Dateien ist der Wert des ersten Enums per Funktion zugewießen. Also alles in allem nicht ganz einfach. Ich hab mir auch mal nen TCL-Parser gebaut aber so richtig dolle war der auch nicht.
    Wird wohl auf nen eigenen Lexer rauslaufen. 🙂 .. Hab halt gedacht, es gibt vielleicht eine einfache Lösung...

    Th schrieb:

    Anschließend befinden sich die Daten in der Map (am besten als Klassenvariable deklariert) und du kannst dann damit nach einzelnen Namen mit find() suchen (O(log N)).
    Bei einem Array (oder std::vector) hättest du ja ein lineares Suchverhalten (O(N)), daher die Empfehlung für das Array (insebsondere bei mehreren Hundert oder mehr Einträgen).

    So aus dem Gefühl raus, vermute ich mal du wolltest mir die Map empfehlen weil hier das suchen schneller geht. Aber das ist erst mal nicht so das Thema, da ich Zeit habe und hier nicht so die Priorität ist. Wichtig ist die Funktion 🙂 erstmal.

    Grüßle Oli


Anmelden zum Antworten