Prä-Dekrement im Index eines Array erzeugt falschen Wert [gelöst]



  • Hi Gemeinschaft,

    mir ist da in meinem C++Builder3 etwas Merkwürdiges aufgefallen:

    Ich hab' ein unsigned-char-Array mit 4 Elementen.

    unsigned char Buff[4]= {0x00, 0x00, 0x00, 0x00};
    

    Zusätzlich habe ich eine Variable, in der ich den Index des Array darstelle.

    int BuffIndex= 4;
    

    Wenn ich jetzt einen Wert in das Array einfügen will, zB. so:

    Buff[--BuffIndex]= 0xFF;
    

    dann ist nach Ausführung der Zeile BuffIndex=2, dabei war vorher BuffIndex=4 !!! 😕

    Was soll das? Wo liegt der Haken?

    MfG



  • Hallo

    Kann ich mit dem Builder 5 nicht nachvollziehen (was mich auch stark gewundert hätte)

    #include <iostream>
    
    int main(int argc, char* argv[])
    {
      unsigned char Buff[4]= {0x00, 0x00, 0x00, 0x00};
      int BuffIndex= 4;
      Buff[--BuffIndex]= 0xFF;
      std::cout << "BuffIndex : " << BuffIndex << ", Array : " << int(Buff[3]) << std::endl;
    }
    

    Ausgabe ist wie erwartet : <3> und <255>

    Vermutlich wird dein -- zweimal aufgerufen bevor du es ausgeben läßt.

    bis bald
    akari



  • Hallo,

    ich habe das Ganze im Schrittbetrieb kontrolliert (F7); Vor der Zeile

    Buff[--BuffIndex]= 0xFF;
    

    ist BuffIndex 4, danach 2... Anzeigen lasse ich mir BuffIndex in der "Liste überwachter Ausdrücke".

    Selbst wenn ich Folgendes schreibe:

    --BuffIndex;
    Buff[BuffIndex]= 0xFF;
    

    ist nach Ausführung von Zeile 1 BuffIndex 2 (vorher 4)...

    Allerdings sieht bei mir der reale Code etwas anders aus:

    Buff[BuffIndex]= TempBuff[i];
    

    wobei i ein Integer-Schleifenzähler ist und TempBuff ein unsigned-char-Array mit 520 Elementen. Ich denke aber nicht, dass dies eine Rolle spielt!?!

    Mit Post-Dekrement funktioniert's übrigens:

    BuffIndex--;
    Buff[BuffIndex]= TempBuff[i];
    

    Ich kann mir da keinen Reim drauf machen. 😞

    MfG



  • Zeig bitte mal deinen Code. Schreibst du evtl. irgendwo in Speicher der dir nicht gehört?



  • Keine Ahnung was los war, inzwischen geht's auch mit

    --BuffIndex;
    

    😕
    Die problematische Stelle ist mit Ausrufezeichen versehen.
    Ich poste mal nicht den ganzen Code der Funktion, sondern nur den Kernteil...
    Leider habe ich die Version nicht mehr, in der es Probleme gab.

    //...
    	TDataModul *DtaModul= new TDataModul(0);									// DatenModul instanziieren
    	const unsigned char Empty[4]= {0x00, 0x00, 0x80, 0x4E};						// Array mit Wert für leere DB-Felder
    	int DBByte= 0, MWNbr= 0, MWByte= 4;											// versch. Zähler
    	unsigned char TmpChar;														// temp. Variable
    	WriteFile(hCOM, &write_ack, 1, &w, &Overlapped);							// Acknowledge an Controller senden
    	BarTimer->Enabled= true;													// Timer f. Fortschrittsanzeige starten
    	for(int k= FFrames; k > 0; k--)												// Loop: volle Blöcke empfangen:
    	{
    		if(!GetFrame(518, 1)) { /*Report(,,);*/ return(false); }				// voller Block erwartet oder Abbruch
    		if(CheckRxFrame(/*true, */0x02, 0x02, 0x44, 518))							// Rahmenprüfung
    		{
    			for(int i= 5; i <= 516; i++)										// Loop: Nutzdaten verarbeiten
    			{
    				if(DBByte <= 5)													// wenn Datum-/Stunden-Index:
    				{
    					TmpChar= FrameBuff[i] & 0xF0;								// temp. untere 4 Bits ausblenden
    					if((TmpChar != 0x00) && (DBByte != 5))						// wenn Zehnerstelle vorhanden:
    					{
    						TmpChar= TmpChar >> 4;									// obere 4 Bits nach unten
    						FrameBuff[i]-= (unsigned char)(TmpChar * 0x06);			// BCD-Wert => HEX-Wert
    					}
    					DtaModul->CC.DTBuff[DBByte++]= FrameBuff[i];				// Jahr/Monat/Tag/Stunde/Minute übergeb.
    				}
    				else
    				{
    					if(MWByte==4) TmpChar= Konfigur[99 + MWNbr];
    					MWByte--;													// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    					if((TmpChar!=0x00) && (DtaModul->CC.DTBuff[5]%TmpChar==0))	// wenn akt. Minute zum Intervall passt:
    						DtaModul->DBS.Wert.Byte[(MWNbr*4)+MWByte]= FrameBuff[i];
    					else
    						DtaModul->DBS.Wert.Byte[(MWNbr*4)+MWByte]= Empty[MWByte];
    					DBByte++;
    					if(MWByte==0)
    					{ MWByte= 4; MWNbr++; }
    				}
    				if(DBByte==70)
    				{ DtaModul->WriteToDB(); DBByte=0; MWNbr= 0; }
    			}
    			usFrameCnt++;														// Rahmenzähler + 1
    			if(FFrames>=294)													// wenn mehr als 293 volle Rahmen:
    			{
    				if((sSubPx>=1) && (usFrameCnt>NoPxStep))						// wenn mind. 1 Subtr.pix. & Subtr.rahm.
    				{ sSubPx--; usFrameCnt= 0; }									// Subtr.pix.-1 & Rahmenzähler Reset
    			}
    			else sSubPx-= (short)(293/FFrames);									// bis 293 Rahmen: Subtr.pix.-293/Rahmen
    			Application->ProcessMessages();
    			WriteFile(hCOM, &write_ack, 1, &w, &Overlapped);					// Ack, wenn Alles iO
    		}
    		else
    		//...
    	}
    	//...
    

    @ Braunstein: Deiner Frage entnehme ich, dass der Fehler ein Folgefehler eines anderen Problems war. Das würde erklären, warum es nun funktioniert.
    Dann ist das Problem (welches keines war) wohl gelöst. 🙄



  • Genau das meinte ich. Solche Dreckeffekte können auftreten wenn man vorher irgendwo undefiniertes Verhalten erzeugt hat.



  • Hello again Gemeinschaft,

    ich hoffe ihr seid alle wohlauf!

    Mir ist passend zu diesem Thema mal etwas aufgefallen, was - im Nachhinein gesehen - wohl eine Menge Probleme verursacht hat, vielleicht auch das Problem in diesem Thema: Ich habe mal wieder mit dem C++Builder 3 etwas rumgespielt und festgestellt, dass durch blosses Ansehen eines Berechnungsergebnisses im Debugmodus (Haltepunkt gesetzt, Programm steht still) Variablenwerte verändert werden!!!

    // Beispiel 1:
    int i= 0;
    i+= 1;
    if(i == 1) MacheWas();
    

    Setze ich in Zeile 2 einen Haltepunkt und gehe mit dem Mauszeiger auf "i+= 1;" nachdem das Programm anhält, wird mir mit Mauszeiger auf "i" folgender Hinweis angezeigt: i= 0; und mit Mauszeiger auf "1" folgender Hinweis: 1=1.

    Verändere ich nun den Code zu Folgendem:

    // Beispiel 2:
    int i= 0;
    (i+= 1);                                // Berechnung in Klammern
    if(i == 1) MacheWas();
    

    sieht es anders aus: Auf "i" und "1" erhalte ich dieselben Hinweise wie beim ersten Versuch, jedoch erhalte ich nun zusätzlich mit Mauszeiger auf ")" den Hinweis: (i+= 1) = 1. So weit, so gut...
    Wenn ich das Programm nun fortsetze wird die Funktion in Zeile 3 nicht ausgeführt...! Warum? Die Berechnung in Zeile 2 wurde bei (angeblich) still stehendem Programm ausgeführt und das Ergebnis wurde i zugewiesen, als ich den Mauszeiger auf der schliessenden Klammer positionert habe. Bei Fortsetzung des Programms wird die Berechnung erneut ausgeführt und in i steht eine 2, statt - wie erwartet - einer 1.

    Das Spiel kann beliebig weiter getrieben werden: Positioniere ich bei still stehendem Programm den Mauszeiger immer wieder neu auf ")" in Zeile 2 des zweiten Beispiels, wird i jedes Mal um 1 erhöht... Ich war etwas perplex als ich das herausgefunden habe!

    Gibt es das Problem auch noch in späteren Borland-IDE's oder ist es sogar gar kein Problem, sondern erwünscht?

    MfG



  • Kolumbus schrieb:

    Mir ist passend zu diesem Thema mal etwas aufgefallen, was - im Nachhinein gesehen - wohl eine Menge Probleme verursacht hat, vielleicht auch das Problem in diesem Thema: Ich habe mal wieder mit dem C++Builder 3 etwas rumgespielt und festgestellt, dass durch blosses Ansehen eines Berechnungsergebnisses im Debugmodus (Haltepunkt gesetzt, Programm steht still) Variablenwerte verändert werden!!!

    Heisenbehavior 😃

    Kolumbus schrieb:

    Gibt es das Problem auch noch in späteren Borland-IDE's oder ist es sogar gar kein Problem, sondern erwünscht?

    In C++Builder 2009 wird für (i += 1) kein Tooltip angezeigt, für (i + 1) hingegen schon. Der Debugger ist anscheinend mittlerweile in der Lage, zwischen Statements mit und ohne Auswirkung zu unterscheiden.
    Wenn du den Ausdruck stattdessen bei "Auswerten/Ändern" eingibst, wird er natürlich ausgeführt.



  • audacia schrieb:

    Heisenbehavior 😃

    Ich bin zwar ein Freund von Verschwörungstheorien, hier denke ich jedoch: es ist einfach ein Fehler... 😃


Anmelden zum Antworten