Fehlermeldung beim Compilieren ohne Dynamische RTL verwenden



  • Hallo Community,

    ich habe eine Anwendung geschrieben, die ich nun auf einem Rechner laufen lassen möchte, auf dem nicht Borland Builder installiert ist.

    Wenn ich nun, in den Projektoptionen unter Linker den Hacken für Dynamische RTL verwenden und unter Packeges den Hacken für Mit Laufzeit Packeges aktualisieren entferne, damit mir ein Lauffähiges EXE Programm entsteht, dann bekomme ich die Fehlermeldung:

    Im Projekt ist eine Exception der Klasse EAccessViolation aufgetreten. Meldung:'Zugriffsverletzung bei Adresse 0055B94D. Lesen von Adresse 00000000'. Prozeß wurde angehalten.

    Wenn ich die Meldung mit OK bestätige bleibt er mir dann in der Datei _ios.c stehen.
    Pfad:

    template <class _CharT, class _Traits>
    basic_ios<_CharT, _Traits>::basic_ios()
      : ios_base(),
        _M_fill(_STLP_NULL_CHAR_INIT(_CharT)), _M_streambuf(0), _M_tied_ostream(0)
    {}
    

    Es muß an den Dynamischen RTL liegen, da ich versucht habe den Hacken nur bei den Laufzeit Packeges rauszunehmen und da ging es zu compilieren. Habe ich irgendwie defekte Dynamische RTL und wenn ja, wie kann ich sie dann ersetzen oder warum bekomme ich diesen Fehler?

    Grüße
    egcactus



  • Am häufigsten tritt diese Fehlermeldung auf wenn du auf einen nicht initialisierten Pointer zugreifst, meistens ein nicht initialisiertes Objekt.

    Arbeite dein Programm einfach mal Schritt für Schritt durch (F9) und poste hier die Stelle an der die Exception auftaucht.



  • Ich kann das Programm nicht mal starten wenn ich die Dynamischen RTL nicht eingebunden habe. Selbst wenn ich einen Haltepunkt bereits im Hauptformular auf die #include <vcl.h> Anweisung setze, steigt er mir mit diesem Fehler aus. Ich kann sogar die Projekt.cpp Datei nehmen und dort einen Haltepunkt definieren. Aber auch da steigt er mit der Fehlermeldung aus, bevor er zu diesem Haltepunkt gelangt.

    Gibt es eine andere Möglichkeit, wie ich den Fehler finden kann?



  • Meinte natürlich F8 bzw. F7, sorry.
    Starte das Programm mal mit einem Druck auf F7 und step dich durch.



  • Ich weiß nun wo er aussteigt, aber warum verstehe ich nicht

    void CUserDaten::speicherInDatei(CUserDaten Einstellungen)
    {
     // Filename anlegen
     char Filename[140];
    
     // Benutzerverzeichnis holen
     strcpy(Filename,Verzeichnis.getBenutzerordner());
    
     // Verzeichnis einbauen
     strcat(Filename,"\\");
    
     // Benutzername holen
     strcat(Filename,Login->getBenutzer());
    
     // Einstellungen.dat anhängen
     strcat(Filename,"_Einstellungen.dat");
    
     // Datei Benutzer_Einstellungen.dat binär zum Schreiben öffnen
     fstream UserEinstellungen(Filename ,ios::binary|ios::out);
    
     // Benutzerdaten in Datei schreiben
     UserEinstellungen.write((char*)&Einstellungen, sizeof(CUserDaten));
    
     // Datei schließen
     UserEinstellungen.close();
    }
    

    Wie es aussieht hat er mit der Zeile Probleme

    fstream UserEinstellungen(Filename ,ios::binary|ios::out);
    

    Wenn ich das speichern mit dem Filepointer im klassischem C mache geht es aber warum?



  • Schau dir mal an was in Filename steht kurz bevor diese Zeile ausgeführt wird.

    Wahrscheinlich reicht als Lösung aber schon folgendes aus:

    strcat(Filename,"_Einstellungen.dat\0");
    


  • Hallo

    Ich glaube nicht das das Problem an std::fstream liegt, sondern eher wie schon gesagt an ungültigen Speicherzugriffen in deinem Code. Vermutlich bist du dir über die Konsequenzen von solchen binären Speicheroperatoren nicht bewußt, zum Beispiel das sie bei Pointern nur die Adresse des Pointern, nicht aber die eigentliche Instanz hinter dem Pointer speichert. Oder das solche binären Aktionen nicht auf Non-PODs (alles ausser int, float, enum, C-struct...) angewendet werden dürfen.

    Vermutlich beinhaltet deine Klasse CUserDaten einen char* oder AnsiString als Membervariable. Und dann schlägt das einfache binäre Speichern/Lesen fehl, du kommst nicht umhin eine eigene Speicherroutine zu schreiben. Und dann kannst du das binäre Format auch gleich weglassen und im Textformat speichern. Am einfachsten nimmst du dafür TIniFile, was bereits alles bereithält.

    Und ich sehe in deinem Codeauszug keinen Grund warum du bei dem Dateinamen mit C-Strings arbeitest. benutzt lieber AnsiString.

    bis bald
    akari



  • @rean:
    An dem \0 kann es nicht liegen, denn er hat auch Probleme beim Laden (am Beispiel einer ganz anderen Lesefunktion)

    void CLevel::ladeBerechtigung(void)
    {
     // Datei Berechtigungen.dat binär zum Einlesen öffnen
     fstream Berechtigungdaten("Berechtigungen.dat" ,ios::binary|ios::in);
    
     // Wenn öffnen erfolgreich...
     if(Berechtigungdaten)
            {
             // Lese Daten aus Datei
             Berechtigungdaten.read((char*)&access, sizeof(access));
    
             // Datei schließen
             Berechtigungdaten.close();
            }
    }
    

    @akari: Leider weiß ich nicht was Non-PODs sind. Aber ich habe in den Klassen einige char Strings und ich übergebe mit Funktionen zum Teil auch als Pointer Strings in diese hinein und hole sie wieder raus.

    Da sich bei mir aber einige Daten Typen mixen z.B. Char und Integer, wie auch Float, wollte ich die Daten als zusammenhängenden Block speichern.

    Die TIniFile Variante wollte ich nicht nehmen, da ich in einigen Funktionen sehr viele Daten erzeuge, z.B. 10000 Messergebnisse im Floatformat, die ich mit der jeweiligen Komponenete und Masseinheit (char) abspeichere.

    Würdet ihr mir also raten, die Funktionen im Klassischem C Code abzuspeichern und den gesammten Code mal nach fehlerhaften Speicherzugriffen scannen?



  • Hallo

    egcactus schrieb:

    @akari: Leider weiß ich nicht was Non-PODs sind. Aber ich habe in den Klassen einige char Strings und ich übergebe mit Funktionen zum Teil auch als Pointer Strings in diese hinein und hole sie wieder raus.

    Wie ich bereits schrieb : PODs (Plain Old Datatype) sind die klassichen C-Datentypen wie int, char, enum, C-struct, C-Arrays.
    Alles andere sind Non-PODs und dürfen nicht binär gespeichert werden da ihr Speicherlayout potentiel nicht binär serialisierbar ist.

    Da sich bei mir aber einige Daten Typen mixen z.B. Char und Integer, wie auch Float, wollte ich die Daten als zusammenhängenden Block speichern.

    Integer und Float wären nicht das Problem. Ich vermute mal mit Char meinst du nicht einzele char, sondern char*? Und da ist das Problem : Wenn du ein struct mit einem char* hast, dann ist das Speicherlayout eben nicht zusammenhängend. Im struct selber ist nur der Pointer mit Adresse. Beim binären Speichern des structs wird dann nur die Adresse gespeichert, nicht aber der eigentliche Inhalt des C-Strings. Wenn du nun das wieder einliest verweist der char* auf einen ungültigen Bereich und jedes Lesen fürht zu undefiniertem Verhalten, in den meisten Fällen in einer Speicherschutzverletzung.

    Die TIniFile Variante wollte ich nicht nehmen, da ich in einigen Funktionen sehr viele Daten erzeuge, z.B. 10000 Messergebnisse im Floatformat, die ich mit der jeweiligen Komponenete und Masseinheit (char) abspeichere.

    Wenn dir TiniFile zu unhandlich ist kannst du auch selber ein eigenes Format verwenden. Eine andere Möglichkeit ist XML. In modernen Builder-Varianten ist eine entsprechende XML-Klasse mit dabei

    Würdet ihr mir also raten, die Funktionen im Klassischem C Code abzuspeichern und den gesammten Code mal nach fehlerhaften Speicherzugriffen scannen?

    Nein wir raten dir :
    - Verwende char* und char[] nur wenn es absolut nicht anders geht! Ansonsten immer AnsiString
    - Gib deiner Klasse eine manuelle Speicher- und Laderoutine, die eine (Text-) Datei erzeugt. Das einfache binäre Serialisieren klappt bei deiner Klasse (offenbar) nicht mehr. Und verwende dafür C++ oder VCL-Mittel, keine alten C- oder WinAPI-Sachen.

    bis bald
    akari



  • Ok, danke für die Information.
    Werde zwar ein wenig zu tun haben das umzusetzen, sind mittlerweile eine ganze Menge an Klassen, aber es soll ja funktionieren.

    Danke
    egcactus



  • egcactus schrieb:

    Ich kann das Programm nicht mal starten wenn ich die Dynamischen RTL nicht eingebunden habe. Selbst wenn ich einen Haltepunkt bereits im Hauptformular auf die #include <vcl.h> Anweisung setze, steigt er mir mit diesem Fehler aus.

    😃 👍

    akari schrieb:

    Vermutlich beinhaltet deine Klasse CUserDaten einen char* oder AnsiString als Membervariable. Und dann schlägt das einfache binäre Speichern/Lesen fehl, du kommst nicht umhin eine eigene Speicherroutine zu schreiben

    Oft bietet sich im C++Builder auch an, den Datentyp persistent zu machen und über die entsprechenden VCL-Funktionen abzuspeichern (dann hast du auch die Wahl zwischen Binär- und Textformat).


Anmelden zum Antworten