Dateizeiger nach ifstream::putback an falscher Stelle



  • Hallo zusammen.

    Ich parse eine Datei, in der DB-Objekt-Unterschiede durch ein Drittprogramm aufgezeichnet wurden. Die Objektabschnitte haben immer denselben Aufbau. An einer Stelle muss ich eine '}' wieder zurück in den Stream schicken, was auch eigentlich immer funktioniert. Vor kurzem wurde aber eine Datei generiert, die etwas länger ist als gewöhnlich - knapp doppelt so groß wie sonst - was aber kein Problem darstellen sollte, weil ja im Grunde immer dasselbe durchlaufen wird.
    Zum Debuggen speichere ich den aktuellen Dateizeiger und gebe ihn aus:

    getline(is >> ws, strTmpBuffer, '=');
    if(strTmpBuffer == "Target")
    {
        getline(is, strTmpBuffer, ';');
        if( (is >> strTmpBuffer) && (strTmpBuffer == "}") )
        {
            int dateiposV = is.tellg();    // DEBUG
            is.putback(strTmpBuffer[0]);
            dateipos = is.tellg();         // DEBUG
            cout << delta.holeObjIDA() << ": " << (dateiposV - dateipos) << endl;    // DEBUG
    
            break;
        }
    ...
    

    Wie erwartet ist die Differenz immer 1, bis ich zu dieser Stelle komme. Da ist die Differenz plötzlich -3583, d. h., der Zeiger wird plötzlich 3583 Bytes weiter Richtung Dateiende geworfen.

    Kennt einer von euch dieses Verhalten? Vielleicht stehe ich mir tierisch auf der Leitung, aber ich komme da nicht weiter.

    Danke fürs Reinschauen

    Gruß
    Kai



  • Hast du dir die DateiPos Werte mal angeschaut?

    Prinzipiell konvertierst du ein Wert vom Typ streampos in einen Int. Je nach Größe deiner Datei, kann das Fehlschlagen.

    Nehm doch einfach streampos als Typ (oder mit auto automatisch den richtigen Typ). Du kannst streampos Werte Vergleichen (mit == und !=) und auch subtrahieren, wo wieder ein ein Wert vom Typ streampos raus kommt.

    Edit:
    Den Typ von dataipos kenn ich nicht, aber auf jeden Fall konvertierst du hier:

    int dateiposV = is.tellg();
    


  • Ich habe den Typ dann mal von int in streampos geändert:

    streampos dateiposV
    

    Geändert hat sich aber nix. Das Schreiben der Zeilen erfolgt immer an derselben Stelle im Code. Im Idealfall steht da ID: Differenz. Der verhaspelt sich innerhalb eines Objekt, fängt sich aber auch komischer Weise wieder. Die Differenz ist auch nur an dieser einen Stelle nicht korrekt. Danach hat der dann Probleme wieder zurückzufinden. Irgendwann am Ende läuft er wieder richtig.

    Hier mal der Printout (wie gesagt, der Idealfall ist ID: Differenz):

    5146000: 1
    5146001: 1
    5146009: 1
    5146015: 1
    5146023: 1
    5146024: 1
    5146028: 1
    5146031: 1
    5146032: 1
    5146037: 1
    5146048: 1
    5146049: 1
    5146086: 1
    5146087: 1
    5146088: 1
    5146090: 1
    5146097: 1
    5146099: 1
    5146100: 1
    5146103: 1
    5146105: 1
    5146112: -3583
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    : 1
    5146790: 1
    5146800: 1
    5146831: 1
    5146870: 1
    
    Der Vector enthält 129 Elemente
    


  • Was für ein Typ ist dateipos?

    Edit: Genau wärend deines Edits geantwortet. Hatte gedacht, es geht nur um den Wert 1 vs. -3583. Aber da scheint mehr schief zu laufen, was ich aus dem Codeabschnitt grade nicht heraus lesen kann.

    Edit 2: Da schein ja schon was in deinem delta schief zu laufen.



  • Dann hier mal der etwas rationalisierte Quellcode:

    Klasse CDelta (delta.h)

    #include <string>
    #include <fstream>
    #include <vector>
    
    //#include "widen.h"
    
    using namespace std;
    
    struct strctDelta
    {
    	string strChangeTyp;
    	string strZiel;
    };
    
    class CDelta
    {
    private:	string strObjID, strObjName, strObjTyp;
    			string strDatum, strZeit, strVersion;
    			string strZusatzInfo;
    			int	   iDeltaZaehler;
    			vector<strctDelta> vecDelta;
    
    public:		friend int deltaParsen(istream&, vector<CDelta>&);
    
    			CDelta() : iDeltaZaehler(0)
    			{
    			}
    
    			string  holeObjIDA(void) const;
    			wstring holeObjIDW(void) const;
    			string  holeObjNameA(void) const;
    			wstring holeObjNameW(void) const;
    			string  holeObjTypA(void) const;
    			wstring holeObjTypW(void) const;
    			string  holeZusatzInfoA(void) const;
    			wstring holeZusatzInfoW(void) const;
    			int		holeDeltaZaehler(void) const;
    			void	loescheInhalt(void);
    			//int		fuelleDeltaInfoList(HWND);
    };
    
    inline string CDelta::holeObjIDA(void) const
    {
    	return strObjID;
    }
    
    //inline wstring CDelta::holeObjIDW(void) const
    //{
    //	Widen<wchar_t> to_wstring;
    //
    //	return to_wstring(strObjID);
    //}
    
    inline string CDelta::holeObjNameA(void) const
    {
    	return strObjName;
    }
    
    //inline wstring CDelta::holeObjNameW(void) const
    //{
    //	Widen<wchar_t> to_wstring;
    //
    //	return to_wstring(strObjName);
    //}
    
    inline string CDelta::holeObjTypA(void) const
    {
    	return strObjTyp;
    }
    
    //inline wstring CDelta::holeObjTypW(void) const
    //{
    //	Widen<wchar_t> to_wstring;
    //
    //	return to_wstring(strObjTyp);
    //}
    
    inline string CDelta::holeZusatzInfoA(void) const
    {
    	return strZusatzInfo;
    }
    
    //inline wstring CDelta::holeZusatzInfoW(void) const
    //{
    //	Widen<wchar_t> to_wstring;
    //
    //	if(strZusatzInfo == "")
    //		return L"";
    //	else
    //		return to_wstring(strZusatzInfo);
    //}
    
    inline int	CDelta::holeDeltaZaehler(void) const
    {
    	return iDeltaZaehler;
    }
    
    void CDelta::loescheInhalt(void)
    {
    	iDeltaZaehler = 0;
    	vecDelta.clear();
    	strObjID.clear();
    	strObjName.clear();
    	strObjTyp.clear();
    	strZusatzInfo.clear();
    }
    
    /*int CDelta::fuelleDeltaInfoList(HWND hDeltaList)
    {
    	unsigned int i;
    	string strDeltaInfo;
    	Widen<wchar_t> wstrDeltaInfo;
    
    	strDeltaInfo.clear();
    	for(i = 0; i < vecDelta.size(); i++)
    	{
    		strDeltaInfo += vecDelta[i].strChangeTyp.c_str();
    		strDeltaInfo += " : ";
    		strDeltaInfo += vecDelta[i].strZiel.c_str();
    		SendMessage(hDeltaList, LB_INSERTSTRING, (WPARAM) i, (LPARAM) (wstrDeltaInfo(strDeltaInfo)).c_str());
    		strDeltaInfo.clear();
    	}
    
    	return 0;
    }*/
    

    Konstanten (makros.h)

    #define ID_BN_TEST			  0
    #define ID_GB_KONFIGLISTE	  1
    #define ID_GB_FLEXLISTE		  2
    #define ID_LV_KONFIGLISTE	  3
    #define ID_LV_FLEXLISTE		  4
    #define ID_SB_INFO			 11
    #define ID_TB_TOOLBAR		 13
    
    #define ANZ_BTNS			  7
    
    #define FM_NULL				 20	// Flexlist-Modi
    #define FM_DELTA			 21
    #define FM_OBJECT			 22
    
    #define MY_SELCHANGE		  0	// eigene Nachricht für Zeilenwechsel
    
    // *** Makros zum Parsen (Anfang) ***
    #define HOLE_ABSCHNITT		0x0001
    #define OBJ_START			0x0002
    #define OBJ_PROP			0x0004
    #define PROP				0x0008
    #define CHANGE				0x0010
    #define CODE				0x0020
    
    #define NUR_IN_QUELLE		0x0100
    #define NUR_IN_ZIEL			0x0200
    
    #define RESET(maske)			(	maske = maske ^ maske | HOLE_ABSCHNITT	)
    #define START(maske)			(	maske = maske ^ maske | OBJ_START		)
    #define SET_OBJ_PROP(maske)		(	maske = maske ^ maske | OBJ_PROP		)
    #define SET_PROP(maske)			(	maske = maske ^ maske | PROP			)
    #define SET_CHANGE(maske)		(	maske = maske ^ maske | CHANGE			)
    #define SET_CODE(maske)			(	maske = maske ^ maske | CODE			)
    #define SET_NUR_ZIEL(maske)		(	maske = maske ^ maske | NUR_IN_ZIEL		)
    // *** Makros zum Parsen (Ende) ***
    

    Hauptprogramm (Quelle.cpp)

    #include <iostream>
    
    #include "makros.h"
    #include "delta.h"
    
    int deltaParsen(istream&, vector<CDelta>&);
    
    int main()
    {
    	ifstream		is("DELTA.txt");
    	vector<CDelta>	vecDelta;
    
    	deltaParsen(is, vecDelta);
    
    	/*
    	vector<CDelta>::const_iterator iter;
    	for(iter = vecDelta.begin(); iter != vecDelta.end(); iter++)
    		cout << iter->holeObjIDA() << endl;
    	*/
    	cout << endl << "Der Vector enth" << static_cast<unsigned char>(132) << "lt " << vecDelta.size() << " Elemente" << endl;
    	cin.get();
    	return 0;
    }
    
    // *******************  DELTA-Datei parsen  (Anfang)  *******************
    template <char ATag>
    istream& shiftToChar(istream& is)
    {
    	string strShift;
    
    	getline(is, strShift, ATag);
    
    	return is;
    }
    
    /*template<char ATag, char ETag>
    struct strctToken
    {
    private:	string& token;
    
    public:		strctToken(string& strrefToken) : token(strrefToken)
    			{
    			}
    
    			friend istream& operator>>(istream& is, strctToken& tok)
    			{
    				return getline(is >> shiftToChar<ATag>, tok.token, ETag);
    			}
    };*/
    
    inline void fuelleZiel(string& rstrTmpBuffer, strctDelta& rstrctDeltaBuffer)
    {
    	if(rstrTmpBuffer[rstrTmpBuffer.length() - 1] == ';')
    		rstrTmpBuffer.pop_back();
    	rstrctDeltaBuffer.strZiel += rstrTmpBuffer;
    }
    
    int deltaParsen(istream& is, vector<CDelta>& rvecDelta)
    {
    	string		 token, strTmpBuffer;
    
    	string		 strStatus;
    	strctDelta	 strctDeltaBuffer;
    	short		 sObjAbschnitt	= 0;
    	int			 iLevel			= 0;
    	int			 iAux;
    	bool		 bNurInZiel		= false;	// temporär
    	CDelta		 delta;
    	streamoff	 dateipos=0;				// DEBUG
    
    	while(true)
    	{
    		if(is.eof())
    			break;
    
    		// is >> token;
    		// DEBUG
    		if(dateipos == 126917 || dateipos == 120302)	// 130558
    			dateipos = dateipos;
    		// DEBUG
    		dateipos = is.tellg();	// DEBUG
    		if(!(is >> token))
    			continue;
    		dateipos = is.tellg();	// DEBUG
    
    		// if(delta.strObjID == "5146350")
    		//	strTmpBuffer = strTmpBuffer;
    
    		if(token == "OBJECT")
    		{
    			START(sObjAbschnitt);
    			continue;
    		}
    		else if(token == "OBJECT-PROPERTIES")
    		{
    			if((sObjAbschnitt & 0xFF00) != NUR_IN_ZIEL)
    				SET_OBJ_PROP(sObjAbschnitt);
    			continue;
    		}
    		else if(token == "PROPERTIES")
    		{
    			if((sObjAbschnitt & 0xFF00) != NUR_IN_ZIEL)
    				SET_PROP(sObjAbschnitt);
    			continue;
    		}
    		else if(token == "CHANGES")
    		{
    			if((sObjAbschnitt & 0xFF00) != NUR_IN_ZIEL)
    				SET_CHANGE(sObjAbschnitt);
    			continue;
    		}
    		else if(token == "CODE")
    		{
    			if((sObjAbschnitt & 0xFF00) != NUR_IN_ZIEL)
    				SET_CODE(sObjAbschnitt);
    			continue;
    		}
    
    		if(token == "{")
    		{
    			iLevel++;
    			if(((sObjAbschnitt & HOLE_ABSCHNITT) == HOLE_ABSCHNITT))
    				continue;
    		}
    
    		if(token == "}")
    		{
    			if(!--iLevel)
    			{
    				rvecDelta.push_back(delta);
    				memset(&strctDeltaBuffer, 0, sizeof(strctDelta));
    				delta.loescheInhalt();
    			}
    			else
    			{
    				if( (iLevel == 1 && (sObjAbschnitt & 0xFF00) != NUR_IN_ZIEL) || 
    					(iLevel == 0 && (sObjAbschnitt & 0xFF00) == NUR_IN_ZIEL) )
    					RESET(sObjAbschnitt);
    			}		
    			continue;
    		}
    
    		if((sObjAbschnitt & 0xFF00) == NUR_IN_ZIEL)
    			continue;
    
    		if((sObjAbschnitt & 0x00FF) == HOLE_ABSCHNITT);
    		else if((sObjAbschnitt & 0x00FF) == OBJ_START)
    		{
    			strStatus = token;
    			if(strStatus == "Modification")
    			{
    				getline(is >> shiftToChar<'"'>, delta.strObjName, '"');
    				getline(is >> shiftToChar<'('>, delta.strObjTyp, ' ');
    				getline(is, delta.strObjID, ')');
    			}
    			else if(strStatus == "Table"	||
    					strStatus == "Report"	||
    					strStatus == "Codeunit"	||
    					strStatus == "XMLport"	||
    					strStatus == "Page")
    			{
    				//Objekt nur in Ziel
    				SET_NUR_ZIEL(sObjAbschnitt);
    				delta.strObjTyp = strStatus;
    				delta.strZusatzInfo = "Objekt fehlt in Quelle";
    				getline(is >> shiftToChar<' '>, delta.strObjID, ' ');
    				getline(is, delta.strObjName);
    				strctDeltaBuffer.strChangeTyp = "Source Deletion";
    				strctDeltaBuffer.strZiel = delta.strObjTyp;
    				delta.vecDelta.push_back(strctDeltaBuffer);
    				delta.iDeltaZaehler++;
    
    				continue;
    			}
    			RESET(sObjAbschnitt);
    		}
    		else if((sObjAbschnitt & 0x00FF) == OBJ_PROP)
    		{
    			getline(is >> shiftToChar<'='>, delta.strDatum, ';');
    			getline(is >> shiftToChar<'='>, delta.strZeit, ';');
    			getline(is >> shiftToChar<'='>, delta.strVersion, ';');
    			if((delta.strVersion == "Yes") || (delta.strVersion == "No"))
    				getline(is >> shiftToChar<'='>, delta.strVersion, ';');
    			RESET(sObjAbschnitt);
    		}
    		else if((sObjAbschnitt & 0x00FF) == PROP)
    		{
    			while(true)
    			{
    				getline(is >> ws, strTmpBuffer, '=');
    				dateipos = is.tellg();	// DEBUG
    				if(strTmpBuffer == "Target")
    				{
    					getline(is, strTmpBuffer, ';');
    					dateipos = is.tellg();	// DEBUG
    					if( (is >> strTmpBuffer) && (strTmpBuffer == "}") )
    					{
    						streampos dateiposV = is.tellg();	// DEBUG
    						//dateipos = is.tellg();			// DEBUG
    						is.putback(strTmpBuffer[0]);
    						dateipos = is.tellg();				// DEBUG
    						cout << delta.holeObjIDA() << ": " << (dateiposV - dateipos) << endl;	// DEBUG
    						break;
    					}
    					else
    					{
    						if(strTmpBuffer.substr(0, iAux=strlen("ChangeType")) == "ChangeType")
    						{
    							strctDeltaBuffer.strChangeTyp = strTmpBuffer.substr(strlen("ChangeType") + 1, strTmpBuffer.length());
    							strctDeltaBuffer.strZiel = delta.strObjTyp;
    							if(strTmpBuffer.substr(iAux + 1, strlen("Deletion")) == "Deletion")	// evtl. abweichende Werte
    							{
    								strctDeltaBuffer.strChangeTyp = "Destination Deletion";			// Wenn "Deletion", dann strChangeTyp nochmal ändern
    								delta.strZusatzInfo = "Objekt fehlt in Ziel";
    							}
    							delta.vecDelta.push_back(strctDeltaBuffer);
    							delta.iDeltaZaehler++;
    						}
    
    						break;		// ggf. noch andere Zeilen berücksichtigen
    					}
    				}
    			}
    
    			RESET(sObjAbschnitt); 
    		}
    		else if((sObjAbschnitt & 0x00FF) == CHANGE)
    		{
    			static bool bZielVorh;
    
    			if(	token == "CodeModification"		 ||
    				token == "Deletion"				 ||
    				token == "Insertion"			 ||
    				token == "Modification"			 ||
    				token == "PropertyDeletion"		 ||
    				token == "PropertyInsertion"	 ||
    				token == "PropertyModification"	 ||	token == "PropertyModification;" ||
    				token == "Move")
    			{
    				if(token.substr(token.length() - 1, 1) == ";")
    					token.pop_back();
    				bZielVorh = false;
    				strctDeltaBuffer.strChangeTyp = token;
    				delta.iDeltaZaehler++;
    
    				continue;
    			}
    			else if(token.substr(0, strlen("Target=")) == "Target=")
    			{
    				bZielVorh = true;
    
    				if(strctDeltaBuffer.strChangeTyp == "CodeModification")
    					strctDeltaBuffer.strZiel = token.substr(strlen("Target="), token.length());
    				else
    					if(strctDeltaBuffer.strChangeTyp == "Deletion")
    					{
    						strctDeltaBuffer.strZiel = token.substr(strlen("Target="), token.length());
    					}
    				else
    				{
    					strctDeltaBuffer.strZiel = token.substr(strlen("Target="), token.length());
    					getline(is, strTmpBuffer);
    					if(strTmpBuffer != "")
    						fuelleZiel(strTmpBuffer, strctDeltaBuffer);
    					else
    					{
    						if(strctDeltaBuffer.strZiel[strctDeltaBuffer.strZiel.length() - 1] == ';')
    							strctDeltaBuffer.strZiel.pop_back();
    					}
    				}
    				delta.vecDelta.push_back(strctDeltaBuffer);
    
    				continue;
    			}
    			else if(token.substr(0, strlen(";Target=")) == ";Target=")
    			{
    				bZielVorh = true;
    
    				strctDeltaBuffer.strZiel = token.substr(strlen(";Target="), token.length());
    				getline(is, strTmpBuffer);
    				if(strTmpBuffer != "")
    					fuelleZiel(strTmpBuffer, strctDeltaBuffer);
    				else
    				{
    					if(strctDeltaBuffer.strZiel[strctDeltaBuffer.strZiel.length() - 1] == ';')
    						strctDeltaBuffer.strZiel.pop_back();
    				}
    				delta.vecDelta.push_back(strctDeltaBuffer);
    
    				continue;
    			}
    			else if( (token.substr(0, strlen("Property=")) == "Property=") ||
    					 (token.substr(0, strlen(";Property=")) == ";Property=") )
    			{
    				if(!bZielVorh)	// Property ohne vorheriges Target
    				{
    					strctDeltaBuffer.strZiel = token.substr(strlen("Property="), token.length());
    					getline(is, strTmpBuffer);
    					if(strTmpBuffer != "")
    						fuelleZiel(strTmpBuffer, strctDeltaBuffer);
    					else
    					{
    						if(strctDeltaBuffer.strZiel[strctDeltaBuffer.strZiel.length() - 1] == ';')
    							strctDeltaBuffer.strZiel.pop_back();
    					}
    					delta.vecDelta.push_back(strctDeltaBuffer);
    				}
    
    				continue;
    			}
    			else
    				continue;
    
    			// RESET(iObjAbschnitt);	// kein RESET da mehrfacher Durchlauf - Umstellung iObjAbschnitt, wenn token == "CODE"
    		}
    		else if((sObjAbschnitt & 0x00FF) == CODE)
    		{
    			continue;
    		}
    
    	}
    
    	return 0;
    }
    // *******************  DELTA-Datei parsen  (Ende)  *******************
    

    Die Stelle

    is.putback(strTmpBuffer[0]);
    

    ist die, wo das '}' wieder zurückgeschoben wird.

    Die Stelle

    if(dateipos == 126917 || dateipos == 120302)
    			dateipos = dateipos;
    

    nutze ich, um einen Haltepunkt zu setzen. Die erste ist die Stelle an der PROPERTIES im "fehlerhaften" Objekt steht und die zweite ist die Stelle PROPERTIES im Objekt davor, wo noch alles gut zu sein scheint.

    Vielleicht hilft das weiter.



  • Selten so einen grauenvollen Parsercode gesehen.

    Warum benutzt du nicht Boost.Spirit?

    Eine (kleine) Auswahl deiner Fehler:
    - Weißt du was

    maske = maske ^ maske | HOLE_ABSCHNITT
    

    macht? Und wenn, warum so sinnlosen Code?
    - daher sind (bisher) die Abfragen mittels

    (sObjAbschnitt & 0xFF00)
    

    genauso sinnlos
    - memset auf Struktur mit std::string Datentypen ist UB
    - Zeile 140: (iLevel == 0) kann dort nie erfüllt sein (wegen der if-Abfrage vorher)
    - ...



  • Tut mir ja Leid, aber der Code funktioniert so wie der da steht. Ich bezweifele auch, dass das irgendwas mit der fehlerhaften Funktion zu tun hat.
    Wenn der Zeiger auf Byte x steht, dann sollte er nach dem putback auf x-1 stehen. Der Rest meines Codes hat sicher nix damit zu tun und wenn ja, dann sage mir mal wo.



  • Bevor ich den Code im Detail durch gehe. Hast du dir die Werte von dateiposV und dateipos mal einzeln angeschaut?
    Vielleicht gibt tellg ja z.B. einen Fehler (-1) zurück.



  • Habe ich auch schon überprüft - ist alles gut soweit. Ich werde gleich mal den Inhalt zweier solcher Dateien schicken. Einen der funktioniert und den der Probleme macht.



  • Ich habe mal versucht, deinen Code zu lesen... und ich möchte dir, auch wenn du es wahrscheinlich nicht hören willst, ein paar allgemeine Sachen dazu sagen:

    Um ehrlich zu sein, Objekt orientierter C++ Code sieht anders aus... Für mich sieht das nach einem ungesunden Mischmasch aus C und C++ aus.

    Die ganzen voids als Funktion Parameter kannst du dir in C++ einfach sparen.

    Und auf Makros würde ich in C++ ganz verzichten, die sind nur fehleranfällig.

    Eine while Schleife, deren Ende nur durch Breaks bestimmt wird und deren "neuanfang" nur durch contiunues besteht, ist auch nicht besonders schön. Vor allem bei der Länge der Schleife. Das hat immer was von "goto anfang" und "goto end".

    Was willst du damit erreichen?

    if(!(is >> token))
       continue;
    

    Fehler im Stream überprüft man mit failbit oder badbit. Und sonst, wenn die Operation ein Fehler zurück liefert, versuch es im nächsten Schleifendurchlauf nochmal?

    Insgesamt habe ich das Gefühl, dass du dir die meisten continues auch sparen könntest. Eine der Nachfolgenden Bedingungen kann dann doch eh nicht mehr wahr werden.

    Zu Memset hat Th69 ja schon was geschrieben.

    Es sind insgesamt viele Dinge, die es schwer machen den Fehler zu finden.

    Ein gut gemeinter Tipp: Teile deinen Code in mehrere Funktionen auf, dass macht es auch einfacher zu debugen.

    Es kann natürlich auch sein, dass deine Datei nicht im erwarteten Format vorliegt.



  • Die continues setze ich lediglich da, wo ein Durchlaufen bis zum Ende sinnlos ist, ist eine gewisse Verarbeitung, meines Erachtens beendet, dann springe ich aus der Schleife raus. Wenn ich an eine Stelle wie PROPERTIES komme und danach gewisse Dinge brauche, dann springe ich an eine Stelle im Code, die mir diesesn Abschnitt anders zerlegt als die anderen und dann springe ich wieder an den Anfang der Schleife. Ich brauche aus den verschiedenen Abschnitten unterschiedliche Dinge und mit dem Programm lief das auch bisher immer sehr gut.

    Was die Mischung zwischen C und C++ angeht: Wie sieht denn dann "reiner" C++-Code aus - eine Klassen- und Template-Benutzung nach der anderen? Vergleiche, Anweisungen, Zuweisungen - das unterscheidet sich doch nicht großartig von C.

    Was ich nicht verstehe ist die Sache mit memset. Ich weiß nicht, was das Problem damit ist. Der Speicherbereich wird doch nur von Beginn der Variablen bis zu ihrem Ende mit Nullen überschrieben. Kann ich auf andere Weise noch 0.000000000000001 Sekunde rausholen oder quält diese Anweisung die CPU?

    Fakt ist, dass eine solche Differenzdatei (durchschnittlich 220 kB groß) in einer gefühlten halben Sekunde durchlaufen wird, und da ist dann auch noch das Füllen einer visuellen List mit dabei - wie gesagt, der Code ist auf das wesentliche reduziert. Und dadurch, dass ich mit bitweisen Anweisungen arbeite und nicht mit Schlüsselworten wie AND oder OR oder XOR oder erst zuweise und vergleiche, ergibt im übersetzten Programm bestimmt keinen Nachteil.



  • Hier der Inhalt der Datei die Ärger macht: http://codepad.org/sy9VExXs

    Edit durch Arcoth: Code ausgelagert.



  • Und hier mal der Inhalt einer Datei bei der es funktioniert: http://codepad.org/cVRwe9BS

    Edit durch Arcoth: Code ausgelagert.



  • Wegen memset lies dir mal memset() or value initialization to zero out a struct? durch (ich hoffe, du weißt, was POD bedeutet?).

    Und hast du mal den Ratschlag getestet?

    Schlangenmensch schrieb:

    Hast du dir die Werte von dateiposV und dateipos mal einzeln angeschaut?

    Und packe deinen letzten beiden Beiträge in korrekte Code-Tags.


  • Mod

    Code solcher Ausmaße bitte extern hochladen und verlinken. Sonst wird die Navigation in einem solchen Thread erheblich erschwert.



  • Arcoth schrieb:

    Code solcher Ausmaße bitte extern hochladen und verlinken. Sonst wird die Navigation in einem solchen Thread erheblich erschwert.

    Sorry, wußte ich nicht besser. Werde ich in Zukunft so machen.

    Th69 schrieb:

    Wegen memset lies dir mal memset() or value initialization to zero out a struct? durch (ich hoffe, du weißt, was POD bedeutet?).

    Habe ich mir jetzt mal angesehen. Vielen Dank für den Link.

    Th69 schrieb:

    Und hast du mal den Ratschlag getestet?

    Schlangenmensch schrieb:

    Hast du dir die Werte von dateiposV und dateipos mal einzeln angeschaut?

    Das ganze sieht so aus:

    streampos dateiposV = is.tellg();	// DEBUG
    is.putback(strTmpBuffer[0]);
    dateipos = is.tellg();			// DEBUG
    

    Bei einem Objekt, dass noch richtig eingelesen wird, hat dateiposV bspw. den Wert 120371 und dateipos nach dem putback 120370. An der Stelle, an der es zu diesem mir nicht verständlichen Verhalten kommt, hat dateiposV den Wert 126975 und nach dem putback enthält dateipos nicht, 126974, sondern 130558.



  • _Bongo schrieb:

    Tut mir ja Leid, aber der Code funktioniert so wie der da steht.

    Falsch ist er trotzdem.

    _Bongo schrieb:

    Ich bezweifele auch, dass das irgendwas mit der fehlerhaften Funktion zu tun hat.

    Kannst du bezweifeln. Muss aber nicht stimmen. Als erstes sollte man mMn. mal grobes UB wie z.B. das memset auf std::string fixen - also bevor man anfängt gross Fehler zu suchen. Für so "daran kann es nicht liegen" Einschätzungen braucht es speziell bei C++ einiges an Erfahrung - und selbst die alten Hasen vertun sich da manchmal.

    _Bongo schrieb:

    Wenn der Zeiger auf Byte x steht, dann sollte er nach dem putback auf x-1 stehen. Der Rest meines Codes hat sicher nix damit zu tun ...

    Dann sollte es für dich ja möglich sein ein kleines Beispiel mit 10-20 Zeilen zu basteln welches das selbe Verhalten zeigt.

    _Bongo schrieb:

    ...und wenn ja, dann sage mir mal wo.

    Wenn ich das wüsste würde ich es dir vermutlich sogar sagen. Nur suchen werde ich nicht. Das ist deine Aufgabe. Und da die Ursachen für solche Fehler oft nicht auf den 1. Blick zu erkennen sind...



  • _Bongo schrieb:

    An der Stelle, an der es zu diesem mir nicht verständlichen Verhalten kommt, hat dateiposV den Wert 126975 und nach dem putback enthält dateipos nicht, 126974, sondern 130558.

    130558 - 126974 = 3584 = 7 * 512
    7 * 512 ist schon sehr verdächtig. Könnte also wirklich ein Bug in der iostream Implementierung sein. Welchen Compiler verwendest du (genaue Version)?

    _Bongo schrieb:

    Was ich nicht verstehe ist die Sache mit memset. Ich weiß nicht, was das Problem damit ist. Der Speicherbereich wird doch nur von Beginn der Variablen bis zu ihrem Ende mit Nullen überschrieben.

    Und genau das darfst du nicht machen. Du darfst nicht einfach so Objekte wie std::string mit Nullen überschreiben. Wie kommst du auf die Idee dass das erlaubt wäre?
    ->

    strctDeltaBuffer.strChangeTyp.clear();
        strctDeltaBuffer.strZiel.clear();
        // oder
        strctDeltaBuffer = strctDelta();
    


  • hustbaer schrieb:

    Und genau das darfst du nicht machen. Du darfst nicht einfach so Objekte wie std::string mit Nullen überschreiben. Wie kommst du auf die Idee dass das erlaubt wäre?

    Nachdem ich mir das mit memset mal durchgelesen habe, schien mir das auch sehr verständlich, dass das keine so gute Idee ist alles zu überschreiben. Ich habe das bereits gestern geändert.

    Der Compiler ist Microsoft Visual Studio Professional 2012 und die Version ist 11.0.61219.00 Update 5



  • Also das ganze scheint zu passieren wenn man genau an einer 4K grenze putback() versucht. Sieht mir nach einem Bug in der MSVC Implementierung aus.*
    putback ist zwar nicht garantiert, aber laut Doku sollte badbit bzw. failbit gesetzt werden. Und das passiert nicht. tellg steht dann auch irgendwo, und als nächstes zeichen kommt nicht das "zurückgestellte". Mit MSVC 2017 verhält es sich etwas anders aber auch nicht korrekt.

    Pragmatische Lösung: vermeide putback einfach grundsätzlich. Du kannst ja vorher mit peek() gucken was kommt, dann hast du im Falle des Falles nix zurückzustellen.

    Programm zum nachstellen:

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cctype>
    
    int main(int argc, char* argv[])
    {
    	int found = 0;
    
    	for (int i = 0xFF0; i < 0x1010; i++) {
    
    		{
    			std::ofstream f("_test.txt", std::ios::binary);
    			for (int j = 0; j < i; j++)
    				f.write(" ", 1);
    			f << "  ; } x---------------------------------------------------------------------------------------------";
    			f.flush();
    			f.close();
    		}
    
    		std::ifstream f("_test.txt");
    
    		std::string str;
    		getline(f, str, ';');
    //		f >> str;
    		str.clear();
    		char c;
    		while (std::isspace(f.peek()))
    			f.read(&c, 1);
    		while (!std::isspace(f.peek())) {
    			f.read(&c, 1);
    			str.push_back(c);
    		}
    
    		auto p1 = f.tellg();
    		f.putback(str[0]);
    		auto s1 = f.rdstate();
    		auto p2 = f.tellg();
    		auto s2 = f.rdstate();
    
    		auto diff = static_cast<long long>(p1 - p2);
    
    		if (diff > 2 || diff < -2 || found) {
    			std::cout << "@" << p1 << ":\n";
    
    			f.read(&c, 1);
    			auto p3 = f.tellg();
    			std::cout << "next char: '" << c << "'\n";
    			f.read(&c, 1);
    			auto p4 = f.tellg();
    			std::cout << "next char: '" << c << "'\n";
    			f.read(&c, 1);
    			auto p5 = f.tellg();
    			std::cout << "next char: '" << c << "'\n";
    			f.read(&c, 1);
    			auto p6 = f.tellg();
    			std::cout << "next char: '" << c << "'\n";
    			found++;
    			if (found > 1)
    				break;
    		}
    	}
    
    	return 0;
    }
    

    Output mit MSVC 2017:

    @4096:
    next char: ' '
    next char: 'x'
    next char: '-'
    next char: '-'
    @4097:
    next char: '}'
    next char: ' '
    next char: 'x'
    next char: '-'
    

    BTW: Kann mir jemand erklären wofür putback eigentlich gut ist? Frag ich mich schon lange. "Könnte sein dass geht, könnte sein dass nicht" ist ja meistens nicht so wirklich hilfreich...
    Oder gibt es für bestimmte konkrete Stream-Typen (z.B. ifstream) stärkere Garantien?

    *: Nah, bin mir nicht mehr so sicher. Nämlich wie die Sache mit dem "last character read" zu interpretieren ist. Die Iostreams müssen nämlich "peeken", und "peeken" liest ja einen Character - auch wenn er dann nicht "konsumiert" wird. Mit "stream.get() + stream.unget()" lässt sich das ganze nämlich nicht reproduzieren, da funktioniert alles. Mit "stream.get() + stream.peek() + stream.unget()" geht es aber wieder nicht. Und da der operator >> mit (istream&, string&) halt peeken muss... wurde ein character "gepeekt" wenn du versuchst "putback" zu machen. D.h. es müssten zwei chars zurückgestellt werden, supported wird aber nur einer. Doof. Keine Ahnung was der Standard dazu sagt. Ich find's komisch (unpraktisch). Aber ich find' sowieso die ganzen iostreams unpraktisch.

    TL;DR: Don't use putback or unget unless you like eating canned worms.


Log in to reply