Fehlermeldung bei globalem vector-Objekt vom Typ string



  • Hi(gh)!

    Um die Fehlermeldungen in meinem im Entstehen begriffenen Grafikanalyseprogramm "yaigat" ("Yadgar's Artificial Intelligence Graphics Analysis Tool") übersichtlicher verwalten zu können (und das sie aufnehmende vector-Objekt nicht jedesmal an jede Funktion, die gegebenenfalls jeweilige Fehlermeldung ausgeben soll übergeben zu müssen), will ich ein vector-Objekt vom Typ string global anlegen, wo ich dann mit dem allmählichen Ausbau des Programms per push_back()-Methode die neu hinzukommenden Fehlermeldungen anfüge.

    Leider spielt g++ nicht mit, ich bekomme immer die Fehlermeldung
    "‘errormsgs’ does not name a type"

    Was denn für ein Typ?

    Bis bald im Khyberspace!

    Yadgar



  • @Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:

    Leider spielt g++ nicht mit, ich bekomme immer die Fehlermeldung
    "‘errormsgs’ does not name a type"

    Es wäre ja echt leichter, wenn du den Quellcode gleich mitposten würdest, der den Fehler verursacht. Du hast da vermutlich einen Syntaxfehler, durch den dein Variablenname errormsgs an einer Stelle steht, wo C++ eine Typbezeichnung erwarten würde. Daher wird der Name als Typ geparst und C++ meckert, dass dieser nicht deklariert wurde.

    Oder errormsgs soll tatsächlich ein Typ sein und du verwendest diesen, bevor dieser deklariert wurde (?).



  • @Finnegan sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:

    Es wäre ja echt leichter, wenn du den Quellcode gleich mitposten würdest, der den Fehler verursacht. Du hast da vermutlich einen Syntaxfehler, durch den dein Variablenname errormsgs an einer Stelle steht, wo C++ eine Typbezeichnung erwarten würde. Daher wird der Name als Typ geparst und C++ meckert, dass dieser nicht deklariert wurde.

    Oder errormsgs soll tatsächlich ein Typ sein und du verwendest diesen, bevor dieser deklariert wurde (?).

    Voilà:

    // yaigat - Yadgar's Artificial Intelligence Graphics Analysis Tool
    
    #define STBI_NO_BMP
    #define STBI_NO_PSD
    #define STBI_NO_HDR
    #define STBI_NO_PIC
    #define STBI_NO_PNM
    
    
    #include <stdlib.h>
    #include <iostream>
    #include <string.h>
    #include <vector>
    #define STB_IMAGE_IMPLEMENTATION
    #include <stb/stb_image.h>
    #define STB_IMAGE_WRITE_IMPLEMENTATION
    #include <stb/stb_image_write.h>
    
    
    using namespace std;
    
    // GLOBALE KONSTANTEN
    
    const string auml = "ä";
    const string Auml = "Ä";
    const string ouml = "ö";
    const string Ouml = "Ö";
    const string uuml = "ü";
    const string Uuml = "Ü";
    const string szlig = "ß";
    const string eacute = "é";
    const string Eacute = "É";
    const string egrave ="è";
    const string Egrave ="È";
    
    // GLOBALE VARIABLEN
    
    vector<string> errormsgs; // Liste der Fehlermeldungen
    errormsgs.push_back("Befehl unbekannt!"); // in parse()
    

    Innerhalb von main() macht eine andere vector-Instanz dagegen kein Problem:

    int main(int argc, char* argv[])
    {
      vector<string> commands; // Liste der Befehle in yaigat
      commands.push_back("-help");
      commands.push_back("-e");
      commands.push_back("-engine");
      commands.push_back("-p");
      commands.push_back("-prompt");
      commands.push_back("-pm");
      commands.push_back("-promptmagic");
      commands.push_back("-rs");
      commands.push_back("-randomseed");
      commands.push_back("-fs");
      commands.push_back("-fixedseed");
      commands.push_back("-m");
      commands.push_back("-model");
      commands.push_back("-rt");
      commands.push_back("-runtime");
      commands.push_back("-w");
      commands.push_back("-weight");
      commands.push_back("-s");
      commands.push_back("-style");
      commands.push_back("-a");
      commands.push_back("-average");
      commands.push_back("-as");
      commands.push_back("-averagesequence");
      commands.push_back("-c");
      commands.push_back("-count");
      commands.push_back("-cq");
      commands.push_back("-countquotient");
    

    Warum?



  • Die Fragen von @Yadgar sind doch Spam... Ich kann hier keine gebotene Sorgfalt erkennen.

    Es tritt ein Fehler auf... ja, toll. Weder die genaue Fehlermeldung, noch der Code, noch der Kontext wird angegeben.

    @Yadgar Sollen das nur Provokationen sein?

    @Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:

    Innerhalb von main()

    Wo ist die schließende Klammer?


  • Mod

    errormsgs.push_back("Befehl unbekannt!");

    Das steht im Nirgendwo. Lektion 0 in C++: Code muss in Codeblöcken stehen. Vielleicht möchtest du dir mal angucken, wie man die Werte von Vectoren bei deren Definition setzt? Oder noch viel besser: Vermeide Anti-Patterns wie veränderliche globale Objekte gleich ganz. Da wirst du nur unglücklich mit.



  • @Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:

    #include <string.h>
    #include <vector>
    ...
    vector<string> errormsgs; // Liste der Fehlermeldungen
    errormsgs.push_back("Befehl unbekannt!"); // in parse()
    

    Gleich vorweg: Du möchtest wahrscheinlich #include <string> und nicht #include <string.h> verwenden. Ersteres holt std::string herein, letzteres ist für C String-Functionen wie strcpy und so'n Kram. Wenn das bei dir nicht zu einem Fehler geführt hat, dann ist das purer Zufall, z.B. weil ein anderer Header std::string für dich eingebunden hat.

    Zu deinem Problem: Du kannst keine "Statements" zwischen den Funktionen schreiben, nur Deklarationen, Definitionen und Variablen-Initialisierungen. Wenn du möchtest, dass errmsgs einen Default-Eintrag bekommt, dann muss du den in einer Initialisierung erzeugen. z.B. so:

    // Liste der Fehlermeldungen
    vector<string> errormsgs = { "Befehl unbekannt!" }; 
    

    Das ist m.E. die sauberste Form für so einen simplen Default-Eintrag. Für komplizierteres kann man auch mithilfe einer Lambda-Funktion initalisieren. Damit kommt man darum herum, dass man nicht einfach "zwischen die Funktionen" irgendwelche v.push_back()-Funtkionen aufrufen kann:

    // Liste der Fehlermeldungen
    vector<string> errormsgs = []{ 
        vector<string> init;
        init.push_back("Befehl unbekannt!");
        return init;
    }(); 
    

    Info: Das "()" am Ende ist wichtig, damit wird nämlich die Lambda-Funktion direkt aufgerufen und der vector mit dem Rückgabenwert initialisiert (Copy-Konstruktion). Merke: das ist immer noch eine Initialisierung, man kann da durchaus Funktionen in dieser Form aufrufen, nur nackte Funktionsaufrufe ohne Initialisierung sind nicht erlaubt.

    Alternativ geht auch so was (ich finde das mit der Lambda-Funktion allerdings eleganter, weil es alles kompakt zusammenhält):

    auto init_errormsgs()
    {
        vector<string> init;
        init.push_back("Befehl unbekannt!");
        return init;
    }
    
    vector<string> errormsgs = init_errormsgs();
    

    Ansonsten: Wenn du nicht unbedingt dynamische Strings benötist, kannst du für solche Fehlermeldungen auch statische Strings verwenden. Eine moderne C++-Variante wäre z.B. diese hier:

    #include <vector>
    #include <string_view>
    
    using namespace std;
    
    // Liste der Fehlermeldungen
    vector<string_view> errormsgs = { "Befehl unbekannt!" }; 
    

    Das kann man so machen, weil solche String-Literale direkt in das Programm eingebettet werden und char*-Pointer auf diese für die gesamte Laufzeit des Programms gültig bleiben. Das ist auch insofern effizienter, da in dieser Form der Compiler den vector direkt in der .data-Section des Programms anlegen kann und dieser dann nicht bei der Programminitialisierung konstruiert werden muss (etwas weniger Arbeit und kompakter in der Executable). Für dynamische Strings erzeugt der Compiler nämlich einen versteckten "Global Constructor", der dann beim Start des Programms automatisch vor main() aufgerufen wird, und der vielleicht so aussehen könnte:

    void __GLOBAL_construct_errormsgs()
    {
        errormsgs.push_back("Befehl unbekannt!")
    }
    

    Ein statisches Objekt hingegen, wie der string_view-Vektor würde stattdessen direkt fertig konstruiert geladen und benötigt eine solche Funktion nicht. Das ist nur ein relativ nebesächliches Detail, aber vielleicht ganz interessant zu wissen (das ist mir nur gerade sehr präsent, weil ich in meinem derzeitigen Hobbyprojekt um jedes Byte in der Binary kämpfe 😉 ).



  • @Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:

    int main(int argc, char* argv[])
    {
    vector<string> commands; // Liste der Befehle in yaigat
    commands.push_back("-help");
    commands.push_back("-e");
    commands.push_back("-engine");
    commands.push_back("-p");
    commands.push_back("-prompt");
    commands.push_back("-pm");
    commands.push_back("-promptmagic");
    commands.push_back("-rs");
    commands.push_back("-randomseed");
    commands.push_back("-fs");
    commands.push_back("-fixedseed");
    commands.push_back("-m");
    commands.push_back("-model");
    commands.push_back("-rt");
    commands.push_back("-runtime");
    commands.push_back("-w");
    commands.push_back("-weight");
    commands.push_back("-s");
    commands.push_back("-style");
    commands.push_back("-a");
    commands.push_back("-average");
    commands.push_back("-as");
    commands.push_back("-averagesequence");
    commands.push_back("-c");
    commands.push_back("-count");
    commands.push_back("-cq");
    commands.push_back("-countquotient");

    Mein Vorschlag wäre, dass Du das wie folgt änderst, wenn während der Laufzeit nichts mehr dazu kommt.

    // N == Anzahl der Befehle in commands
    static constexpr std::array<std::string_view, N> commands = {
        "-help",
        "-e",
        "-engine",
         ...
    };
    
    int main() {
    


  • @john-0 sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:

    static constexpr std::array<std::string_view, N> commands
    

    Ja. Das ist noch besser. std::vector echt nur wenn die Einräge dynamisch sein müssen (zur Laufzeit hinzufügen oder entfernen). Auch für errormsgs.



  • @Yadgar sagte in Fehlermeldung bei globalem vector-Objekt vom Typ string:

    #define STBI_NO_BMP
    #define STBI_NO_PSD
    #define STBI_NO_HDR
    #define STBI_NO_PIC
    #define STBI_NO_PNM

    //#include <stdlib.h>
    #include <iostream>
    //#include <string.h>
    #include <vector>
    #define STB_IMAGE_IMPLEMENTATION
    //#include <stb/stb_image.h>
    #define STB_IMAGE_WRITE_IMPLEMENTATION
    //#include <stb/stb_image_write.h>

    Die nicht auskommentierten Präprozessordirektiven verstehe ich (alle) nicht und ich bin mir fast sicher, dass daran etwas falsch sein muss...

    Die STBI_NO_...-Direktiven sind offizielle Flags von stb_image.h. Da diese vor der Implementierung definiert werden, werden die entsprechenden Decoder (BMP, PSD, HDR, PIC und PNM) gar nicht erst kompiliert. Das spart Platz in der finalen ausführbaren Datei. Aktiv bleiben damit standardmäßig noch beliebte Formate wie PNG, JPEG, GIF und TGA.

    Empfehlung:

    // 1. Standard-Header
    #include <iostream>
    #include <vector>
    
    // 2. Feature-Flags für stb_image
    #define STBI_NO_BMP
    #define STBI_NO_PSD
    #define STBI_NO_HDR
    #define STBI_NO_PIC
    #define STBI_NO_PNM
    
    // 3. Implementierung & Header laden (Pfade ggf. anpassen!)
    #define STB_IMAGE_IMPLEMENTATION
    #include "stb/stb_image.h" 
    
    #define STB_IMAGE_WRITE_IMPLEMENTATION
    #include "stb/stb_image_write.h"
    

    Und beachte: Die Definitionen von STB_IMAGE_IMPLEMENTATION und STB_IMAGE_WRITE_IMPLEMENTATION dürfen insgesamt nur in genau einer einzigen .cpp-Datei des Projekts stehen, da es sonst zu Dublicate Symbol-Fehlern beim Linken kommt.


Anmelden zum Antworten