ich habe ein Programm zum Triangulieren einer Isofläche geschrieben. Die eigentliche Procedure dazu ist in einer Unit ausgelagert und wird über einen Buttonklick gestartet.
1. Frage: Die Procedure soll Statusmeldungen zum debuggen in eine Listbox des Formulars ausgeben. Ich habe dazu meine Listbox als Variable übergeben, so dass ich direkt aus der Procedure zeichnen kann. Das funktioniert auch so. Aber ist das überhaupt "legal" bzw. gibt's da unerwünschte Nebenwirkungen (s.u.)? Gibt's da einen Standardweg für das "zurückleiten" von Meldungen?
2. Frage: Der Code funktionierte soweit. Aber als ich die Listbox.items.add()-Zeilen auskommentiert habe hat sich das Ergebnis meiner Triangulierung geändert und sie produziert irgendwann nur noch Müll. Wohl ein klassischer Heisenbug Schau ich hin geht's, schau ich weg nicht mehr. Wie debugge ich so was? Gibt's da übliche Verdächtige nach denen ich suchen soll?
Das anlegen eines globalen Zeigers auf die Listbox brachte leider keine Besserung. Meine weiteren Ideen wären: - Log in eine Datei schreiben. - letztes stück unverstandenen (copy&paste) Code zur LGS-Lösung untersuchen. - doch noch lernen mit dem Debugger umzugehen. Der Fehler passiert halt irgendwo tief verschachtelt in Schleifen und Unterprogrammen...
Wär echt klasse, wenn Ihr ein paar Tipps hättet oder wenigstens etwas Zuspruch... Solche Fehler regen einen echt auf...
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Prinzipiell ist es für jeden Programmierer eigentlich PFLICHT zu lernen mit dem Debugger umzugehen. Vor allem, da der von Delphi nicht wirklich unbequem ist. Das ist so, als würde ein Autofahrer fragen, ob er sich wirklich mit den Vorfahrtsregeln beschäftigen muss, wegen den 3 Crashes die er gestern an der Kreuzung fabriziert hat.
"Heisenbug" - Den Begriff kannte ich so noch gar nicht. Aber zufällig autretende Fehler deuten üblicherweise auf Pointerfehler hin. Mit sowas habe ich als JAva-Coder zum Glück nix zu tun. Falls du die Möglichkeit hast, solltest du mal so ein Tool zum Prüfen auf Speicherlecks einsetzen. Vielleicht kommst du da näher ran.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Zeiger auf Klassen solltest du dir gar nicht erst angewöhnen. So etwas ist in 99% (+-1%) der Fälle gar nicht nötig und fast immer entstehen genau dadurch die Fehler. Da Klasseninstanzen bereits intern Pointer sind kann man sie einfach so direkt übergeben und benutzt. Außerdem erfordern Pointer etwas mehr Diziplin als pointerloser Code. Es passiert sehr schnell, dass man da in andere Speicherbereiche zugreift und irgendwann irgendwelche Fehler vor die Füße geklatscht bekommt. Deswegen muss man sich immer überlegen ab wann hat man einen Pointer und worauf zeigt der auch.
Was den Debugger angeht. Sich damit auszukennen ist nie verkehrt. Allerdings lassen sich Pointerprobleme nur recht schwer damit finden bzw muss man da mitunter dennoch recht viel Aufwand reinstecken (deswegen die nötige Disziplin, damit so was gar nicht erst passiert). Wenn man erst mal ein bisschen mit dem Debugger warm geworden ist, dann geht das alles viel leichter von der Hand und man möchte ihn später auf gar keinen Fall mehr missen.
Bei deinen Code vermute ich auch, dass du irgendwo Probleme mit einem Speicherzugriff hast. Das kann auch schon ein Arrays sein bei dem du eine Stelle zu viel benutzt. Geh mal in die Optionen deines Projektes auf die Seite "Compiler" und aktiviere alle Laufzeitfehler (wenn sie deaktiviert sein sollten). Ansonsten kann man leider nicht sagen da oder daran liegt es. Die Liste mit klassischen Fehlern kann sehr sehr lang werden. Kommt da auch immer darauf an was du machst. Und ohne Code geht so was schon mal gar nicht.
Zu den Debugausgaben. Wenn das nur zur Überprüfung deiner Arbeitsschritte ist, dann ist da der Debugger defintiv die bessere Wahl. Durch solche Meldungen via Listbox etc kannst du auch das Laufzeitverhalten deines Codes verändern. Also, dass er urplötzlich anders arbeitet. Bzw je nach Aufbau des Codes musst du selbst für simple Meldungen massiv in den Code eingreifen. Alleine der Zeitaufwand den man als Entwickler da rein stecken muss. Wenn du Meldungen aber als Log nach außen reichen willst, dann würde ich da immer eine extra Klasse für erstellen und die Meldungen nur an diese reichen. Was die dann damit macht (VCL Element, Datei, verwerfen) ist deren Sache und brauch den rest Code nicht mehr zu interessieren.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Du scheinst eine Menge Mathematik in deinem Code stecken zu haben. Kann es sein, dass du eine Variable vielleicht versehentlich nicht initialisiert hast? Sowas kann auch zu interessanten Nebenwirkungen führen. Sowas findet sich aber recht gut mit dem Debugger .
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
hat sich das Ergebnis meiner Triangulierung geändert und sie produziert irgendwann nur noch Müll. (...) Gibt's da übliche Verdächtige nach denen ich suchen soll?
Das klingt sehr danach das du von einer nicht initialisierten Speicherstelle Daten liest.
Zitat:
Gibt's da einen Standardweg für das "zurückleiten" von Meldungen?
Eine übliche Lösung ist z.B. eine global verfügbare Funktion "log". Überall wo etwas geloggt werden soll rufst du einfach log("Nachricht blablub") auf. Natürlich kann man auch mehrere Methoden anbieten, etwa "error", "warn", "info" o.ä. Ich implementiere das gerne so, dass hinter dieser Funktion dann eine abstrakte Basisklasse steht, das eigentliche Logging übernimmt dann eine Implementierung des Users. Diese schreibt dann z.B. auf die Standardausgabe oder in eine Datei. In deinem Fall kannst du das dann an deine Listbox weiterleiten. Als Beispiel kann man hier auch das Qt-Framework nennen, dort gibt es eine Funktion qDebug die einfach auf die Standardausgabe schreibt. Durch definieren von QT_NO_DEBUG_OUTPUT kann man den Compiler anweisen sämtliche Aufrufe von qDebug einfach zu ignorieren. Die Debugausgabe kann also einfach im Quellcode bleiben und bei Bedarf wieder aktiviert werden.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Anstatt das selber zu schreiben sollte man eine Log Lib nehmen. Die bietet genau diese Logging-Klasse an, enthält selber keine Fehler und man kann sie bedarfsgerecht configurieren (loglevel, Ausgabe umleiten etc.)
In Java gibts "Log4J", für Pascal müsste das Log4D oder Log4Delphi sein.
Log4D wird wohl noch maintained, aber die Doku ist spärlich. Es gibt aber ne Demo im sourceforge SVN
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Ich bin i.M. noch nicht dazugekommen größer nachzuforschen, daher nur ein paar Anmerkungen.
Also: die Laufzeitfehlerüberprüfung in den Optionen sind eh schon aktiviert, es gibt aber keinen Fehler, auch nicht bei fehlerhaftem Verhalten. An Mathe ist halt die ganze Vektorrechnung, etwas Intervallschachtelung und LGS-lösen drin. Evtl. ist beim LGS der Fehler drin, da ich den Code geklaut hab und noch nicht wirklich verstanden hab. Ich denke, ich werde erstmal mein Glück mit dem Debugger versuchen, zuvor muss ich aber noch die genaue Fehlerstelle finden. Immerhin weiß ich, dass die erste Abweichung beim 28. Durchlauf der Advancing Front, beim 52. Segment und dem Gültigkeitscheck mit Punkt 662 auftritt. Der Punkt steckt aber in 5 anderen Dreiecken drin... Na ja, wir werden sehen... aber nicht mehr heute...
Viele Grüße Boogi @Flash: es gäb da auch noch leckere Mandelbugs...
Aber es wäre doch viel eher im Sinne der Unschärferelation, wenn Heisenbugs, deren zeitliches Auftreten man gut bestimmen kann im Code schwer zu finden wären und solche, die eindeutig gewissen Codezeilen zugeordnet werden können zu völlig unvorhersehbaren Zeiten aufträten...
Und was sind Mandelbugs? Wenn ich einen beseitige kommt dafür ein kleinerer mit den selben Auswirkungen?
Das was du da hast, was erst auftritt, wenn man nicht hinguckt ist eher ein anti-Schrödingerbug...Schrödingerbugs treten dann nur auf, wenn man gerade hinguckt. Oder auch nicht. Und sowas vor dem Zeitalter der Quantencomputer - unglaublich...erinnert alles irgendwie an Java2k
Pack deinen PC in einen Karton, dann ist der Bug da und nicht da... Tschuldigung... Weiter machen!
_________________ Denn wer nur schweigt, weil er Konflikte scheut, der macht Sachen, die er hinterher bereut. Und das ist verkehrt, denn es ist nicht so schwer, jeden Tag zu tun als ob's der letzte wär’. Und du schaust mich an und fragst ob ich das kann. Und ich denk, ich werd' mich ändern irgendwann. _________________Farin Urlaub - Bewegungslos
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Boogi hat geschrieben:
Ich denke, ich werde erstmal mein Glück mit dem Debugger versuchen, zuvor muss ich aber noch die genaue Fehlerstelle finden.
Ne nicht ganz. Das ist mehr oder weniger beides das Selbe. Wenn du schon weißt wo der Fehler ist, dann brauchst du auch keinen Debugger mehr. Der Debugger ist ja eben dazu da um zu überprüfen ob der Code das macht was er machen soll.
Zu aller Erst solltest du mit deiner Anwendung rumspielen. Versuch eine Möglichkeit zu finden wie das Problem immer oder sehr oft auftritt. Manchmal kann man anhand des Verhaltens schon erahnen wo das Problem ist bzw man kann es vielleicht eingrenzen. Wenn nicht, dann setzt einen Breakpoint in deine ButtonOnClick Methode. Und dann musst du durch deinen Code steppen. Zu erst recht Oberflächlich. Und falls du eine Methode überspringst und feststellt, dass die ein inkonsistentes Ergebniss oder einen Fehler produziert, dann setzt du dort einen neuen Breakpoint und springs beim nächsten Versuch in die Untermethode. Und so weiter bis du das entsprechend eingegrenzt hast und die Stelle findest an der es schief geht. Du solltest nur nicht von anfang an komplett in jede kleine Methode rein springen etc. Das wird sonst zu viel. Du musst versuchen den Fehler systematisch einzugrenzen.
Bis ich Fehler richtig eingegrenzt habe brauche ich mitunter auch 10-30 Versuche in denen ich mich immer weiter vor taste. Du darfst nur nicht aufgeben. Falls es zu viel wird. Mach ne Pause oder code erst mal was anderes. Nur nicht aufgeben oder zu verbissen dran sein. An einem Härtefall hatte ich mal 2 Wochen (Vollzeit) mit Unterbrechungen gesessen. Nur um dann festzustellen, dass ein Parameter bei 3 Methoden einen zu kleinen Datentypen hatten. Das Problem trat auch nur beim 27ten Aufruf der Methode auf. Dann aber konsequent immer. Aber ich schweife ab.
Bei Problemen bei denen es um Speicherzugriffsfehler handelt ist es oft sogar so, dass das eigentliche Problem nicht da auftritt wo auch der fehlerhafte Speicherzugriff statt findet. Da muss man teilweise her gehen und an all den Stellen wo auf den Speicher zugegriffen wird einen Breakpoint setzen.
Ich hab's hinbekommen! Beim Erzeugen eines neues Dreiecks wird geschaut, ob ein schon vorhandener Punkt verwendet werden kann. Wird ein potentiell passender gefunden, so wird das neue Dreieck mit allen anderen auf Überlappung gescheckt. Dazu werden die 6 Punkte von jeweils 2 Dreiecken in die Ebene eines der Dreiecke projiziert (LGS). Jeder Punkt hat dann natürlich nur 2 Koordinaten, wird bei mir aber in einem 3D-Vektor gespeichert. Der z-Wert wird dann einfach ignoriert. Blöd nur wenn man dann doch ne Funktion wie betrag() benutzt, die alle 3 Komponenten verwendet... Jetzt wird er brav mit 0 initialisiert.
Erstaunlich, dass der fehlerhafte Code bei zig-tausenden von Dreiecken funktioniert hat...
Mitglieder in diesem Forum: 0 Mitglieder und 15 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.