jQT- Debuggen im Borland C++ Builder

Einige einleitende Worte
Scheinbar gehört es nicht mehr überall in den Programmierunterricht, geschweige denn in die Programmier-LEERbücher, dass man den Leuten das Debuggen - wennauch nur in Ansätzen - erklärt. Und das obwohl es eigentlich genauso zum Programmieren gehört wie das Codieren. Ich würde sogar soweit gehen und sagen, dass es ein wesentlicher Bestandteil des Programmierhandwerks ist.
Einige werden sich fragen, wie ich auf diese Idee komme. Nun ja, ich habe immer öfter festgestellt, dass die Forenteilnehmer zum Teil nichteinmal die Grundbegriffe des Debuggens beherrschen. Nun mag es einige Autodidakten geben, welche keine Hilfe wollen/brauchen, doch ich denke, die Mehrheit arbeitet mit einem Buch, das ihnen die Grundbegriffe von C/C++ vermittelt. Leider habe ich auch selber feststellen müssen, dass sich zwar viele Tutorials und Bücher mit dem Programmieren, aber nur wenige mit dem Debuggen beschäftigen.
Ein möglicher Grund dafür: Das Debuggen kann stark IDE-abhängig sein, und ist deshalb etwas spezialisiert zu behandeln, doch das allein kann's wohl nicht sein. Die Grundbegriffe des Debuggens sind immer gleich, und auch bei verschiedenen IDEs wird doch immer mit Wasser gekocht.
Wie dem auch sei, dem Mangel an Tutorials für's Debuggen möchte ich nun abhelfen. Auch wenn ich mich in diesem Tutorial auf den BCB festlege und ihn als Beispiel heranziehe, so ist vieles hier sicher auch für andere Entwicklungsumgebungen wie MS Visual C++ oder andere verwendbar. Die IDE des Visual C++ mag anders aussehen, die Techniken dahinter sind aber exakt die selben.
Ich denke, es dürfte auch jedem klar sein, dass dieses Tutorial nicht als absolutes Werk und schon gar nicht als umfassend zu bezeichnen ist. Dazu reicht zum Einen meine Zeit nicht, und zum Anderen kenne ich wahrscheinlich selbst nicht mal alle Mittel. Und Ausserdem soll es auch nicht meine Aufgabe sein, hier eine Abhandlung über die IDE zu schreiben, dafür gibt's begabtere und kompetentere Zeitgenossen. Der Artikel soll einen Einstieg in das Debugging vermitteln, er ersetzt allerdings nicht das Erforschen der IDE.

Nun aber genug geplaudert, gehen wirs an!
-junix

Grundsätzliches
An dieser Stelle würden einige wohl eine Erklärung zum Wort "Debuggen" erwarten, aber darauf werde ich verzichten. Wir sind hier schliesslich nicht in einer Deutsch- oder vielmehr Englischstunde. Nur soviel sei verraten: Der deutsche Ausdruck "Da ist der Wurm drin" ist etwa vergleichbar mit dem englischen "There's a Bug" (Da ist ein Käfer).
...Und schon driftete er ab. (;

Debuggen - Das Täglich Brot eines jeden Programmierers. Grundsätzlich schreibt wohl keiner von uns 100% fehlerfreien Code. Fehler können und dürfen passieren, aber man muss sie auch bekämpfen können. Wer hätte gedacht, dass im Schnitt vermutlich mehr als 1/4 der Programmierzeit zum Debuggen eingesetzt wird? (Ein weiteres Viertel geht für die Dokumentation drauf, ein Achtel für Testläufe, ein Achtel sollte man für Notfälle planen und das letzte Viertel dient der eigentlichen Programmierung.) Debuggen ist wahrscheinlich das wichtigste an der Programmierarbeit, und was noch schöner ist: Es macht einen von Foren wie zum Beispiel c-plusplus.de unabhängiger und fördert das allgemeine Verständnis (-;

Jede IDE bietet vergleichsweise bequeme Debugmöglichkeiten an. Die meisten ermöglichen sogar das Setzen von Haltepunkten direkt im Quelltext oder das Step-By-Step Ausführen eines Programms und noch vieles mehr, auf das ich hier noch im Einzelnen eingehen werde.

Wo finde ich die Werkzeuge?

Alle Werkzeuge die im zusammenhang mit dem Debuggen stehen befinden sich im C++ Builder im Menü "Start". Eine Auflistung aller Debugbefehle wäre an dieser Stelle unnnütz. Es sind nämlich alle im Menü "Start" stehenden Befehle!

Die C++ Builder IDE stellt über 5 sehr gute Werkzeuge zur Verfügung:

  • Haltepunkte
  • Quicktip direkt im Quelltextfenster
  • Diverse "Fortbewegungsmöglichkeiten" wie Zeilenweise ausführen, zum Cursor springen, etc.
  • Überwachte Ausdrücke
  • Auswerten/Ändern

Diese 5 Werkzeuge werden wir uns genauer anschauen. Abgesehen von den IDE-Werkzeugen gibt es in der Softwareentwicklung noch ganz andere Möglichkeiten zum Debuggen. Man darf dabei ruhig etwas kreativ sein und eigene Wege beschreiten. Auch von diesen zum Teil doch recht unkonventionellen Methoden werden wir noch einige streifen. Zunächst lernen wir jetzt allerdings diese 5 Standard-Werkzeuge kennen.

Haltepunkte (Breakpoints)

Haltepunkte sind vermutlich die beliebteste Methode eine Software zu debuggen. Wie der Name schon vermuten lässt, ermöglichen Haltepunkte, die Ausführung der Software an einem bestimmten Punkt anzuhalten. Haltepunkte setzt man in der Borland-IDE auf zwei Arten. Entweder über das Menü "Start" oder - was auch wesentlich bequemer ist - mit der Taste F5. Dazu setzt man den Cursor auf die gewünschte Zeile, in der man den Breakpoint (Haltepunkt) haben will und drückt dann eben F5.

Haltepunkte werden im Code durch farbliche Hervorhebung sowie durch zusätzliche Symbole am linken Rand des Editors markiert. Wir unterschieden zwei Arten von Breakpoints: gültige und ungültige. (Vgl. Abb. 1)

Ungültig sind Haltepunkte, an denen der Debugger nicht anhalten kann, weil sich in der entsprechenden Zeile kein (passender) Code befindet. Sie werden wie in Abb. 1 dargestellt zur Laufzeit der Software (also nach dem Start) als ungültig markiert.

Gültige Haltepunkte sind Haltepunkte, an denen der Debugger die Ausführung der Software unterbrechen kann. Gültige Haltepunkte lassen sich grundsätzlich auf jeder Anweisungszeile und auf jeder Endklammer setzen.

Die Frage ist nun wohl, was einem das Anhalten der Software bringen kann. Es gibt mehrere Gründe die Software anzuhalten. Meistens möchte man Variablen überwachen oder den Verlauf einer komplexeren Funktion verfolgen. Für letzteres gibt es mehrere Wege. Der Einfachheit halber beschränken wir uns hier aber auf die beiden wichtigsten.
Wird das Programm über Start->Pause oder über einen Breakpoint gestoppt, so wird die aktuelle Position im Quelltext mit einem grünen Pfeil (Abb. 2) markiert. An diesem Punkt sind wir nun in der Lage, Step By Step durch eine Funktion zu wandern.
Benutzt man den Start->Pause Befehl oder das Pausezeichen der IDE, so springt zunächst das CPU-Fenster auf. Dieses kann man getrost schliessen (ausser man interessiert sich für Assembler *g*) dahinter erscheint dann die IDE mit dem selben Bild als wäre ein Breakpoint gesetzt worden. (Abgesehen von dem nicht vorhandenen Breakpoint *g*)


Abb. 1
Bewegen innerhalb eines gestoppten Programms

Abb. 2

Die beiden Möglichkeiten die ich oben angesprochen habe nenne sich Step In und Step Over oder in Deutsch: Einzelne Anweisung (F7) und Gesamtroutine (F8). Der unterschied ist folgender: Step In springt in eine aufgerufene Unterfunktion und geht diese ebenfalls Step By Step durch. Step Over behandelt einen Funktionsaufruf als eine einzelne Anweisung.
Selbstverständlich kann man auch jederzeit das Programm wieder weiterfahren lassen, bis es zum nächsten Haltepunkt oder zum Programmende kommt. Das lässt sich erreichen indem man im Menü Start die Option "Start" anklickt oder, schneller, die Taste F9 drückt. Sobald das geschehen ist, läuft das Programm weiter, als wäre nichts geschehen.

Das Bewegen allein ist ja noch nicht wirklich spannend, wenn man eine Software debuggen will. Vorallem lässt sich damit der korrekte Ablauf einer Funktion noch nicht nachweisen. Immerhin beeinflussen oft die verschiedensten Variablen den Verlauf einer Funktion. Deshalb bietet die-BCB IDE die Möglichkeit an, den Inhalt einer Variablen zur Laufzeit anzuschauen.

Um das Innere einer Variable zu prüfen gibt es ebenfalls mehrere Möglichkeiten. Der erste wäre es, mit dem Cursor über die gesuchte Variable zu fahren. Nach kurzer Zeit erscheint dann unter dem Mauszeiger ein sogenanntes Tooltip, in dem der Variableninhalt beschrieben ist.
Diese Methode ist zwar schnell, aber gerade beim Step-By-Step Durchlauf und beim Überwachen von mehreren Variablen recht mühsam. Aus diesem Grund gibt es noch eine weitere Möglichkeit: Das Watches-Window, oder in Deutsch die "Überwachten Ausdrücke". (Abb. 3)

Variablen überwachen

Mit einem Rechtsklick in dieses Fenster kann man mit "Ausdruck hinzufügen" einen beliebigen Ausdruck eingeben. Idealerweise Variablen. Belässt man den Variablentyp auf Vorgabe (meistens ist diese Einstellung empfehlenswert) so findet das Fenster automatisch das richtige Format um den Variablenhinhalt darzustellen. Manchmal (z.B. bei einer char-Variablen) kann es interessant sein, den Hex-Wert zu wissen. Dann kann man die Darstellungsart mit Hilfe des Radiobuttons bequem ändern. Auch die zu überwachende Variable lässt sich hier (nachträglich) noch ändern, z.B. von "Memo1->Text" nach "Memo1->Lines->Strings[0]".

Einzelne Variablen lassen sich leicht in die Liste der überwachten Ausdrücke aufnehmen, indem man den Curser in den Variablennamen setzt und dann STRG + F5 drückt.

In diesem Fenster kann man mit einfachen Mitteln relativ viele Variablen gleichzeitig überblicken, was gerade bei komplexeren Funktionen sehr von Interesse sein kann.


Abb. 3

Auswerten/Ändern


Abb. 4

Gerade beim Debuggen von Schleifen kann das Durchsteppen unter Umständen mühsam werden. Vor Allem dann, wenn zum Beispiel eine Schleife eine Liste mit 100 Elementen verarbeitet und beim 98. Element tritt regelmässig der Fehler auf.
Auch für solche Fälle geben uns die besseren IDEs ein Werkzeug in die Hand mit dem sich derartige Probleme vermeiden lassen, indem man die Inhalte der Variablen verändern kann.

Beim Borland C++ Builder heisst diese Option "Auswerten/Ändern" und ist, wie das Überwachen der Variablen entweder im Popupmenü des Programmeditierfensters oder im Menü "Start" zu finden. Wie genau funktioniert nun aber dieses Auswerten und Ändern?

Zunächst tippt man den Ausdruck den man auswerten möchte, in das Feld "Ausdruck" ein. Anschliessend kann man auf den Button "Auswerten" klicken, worauf dann im Abschnitt "Ergebnis" der Inhalt des Ausdrucks zu finden ist. Nun gut, soweit ist das noch nichts besonderes. Dasselbe erreichen wir auch mit dem Watchwindow (Überwachte Ausdrücke). Wie aber kann ich Werte ändern? Wer sich Abb. 4 mal etwas genauer anschaut, wird feststellen, dass das Fenster noch ein drittes, bisher nicht beschriebenes Feld aufweist, das hier allerdings ausgegraut wurde.

Genau dieses Feld dient zum Editieren eines Variablenwertes. Wieso ist es nun aber ausgegraut? Der Grund liegt darin, dass komplexe Datentypen im C++ Builder nicht über diese Methode verändert werden können. Komplexe Datentypen sind zum Beispiel die Klasse "AnsiString" oder andere Typen welche eine interne Speicherverwaltung besitzen. Verändern lassen sich alle Grundtypen wie char, short, int, etc. Um diese Werte zu ändern, tippt man beim Feld "Neuer Wert" den gewünschten neune Wert ein und klickt auf den "Ändern"-Button.

Wenn wir nochmals das obige Beispiel mit der Schleife heranziehen wollen, könnte der Entwickler damit also die Zählvariable auf 97 setzen und dann beobachten wie sich die Schleife bei Durchlauf 98 verhält. Toll, nicht? (:

Eine weitere Möglichkeit ist hier das Definieren von Bedingungen für die Haltepunkte. Um beim Beispiel der langen for-Schleife zu bleiben:

for (int i = 0;i < 100;i++)
{
    //beim 98. Durchlauf crasht die nachfolgende Funktion
    BuggyFunction();
}

Normalerweise müssten wir hier 97 Mal durch die Schleife steppen, um dann im 98sten Durchgang in die Funktion springen und das Problem untersuchen zu können. Stattdessen setze ich bei der BuggyFunction() einen Haltepunkt und greife mit einem Rechtsklick auf das Symbol links neben der Zeile auf die "Breakpoint poroperties" zu. Dort kann ich (für die Schleife am passendsten) den Passcount auf 98 einstellen, oder in Condition eine Bedingung formulieren, wie z.B. "CheckBox1->Checked"

Schlusswort

So, nun solltest du alle grundlegenden Mittel welche dir das Debuggen ermöglichen, zumindest vom Namen her kennen. Ich würde dir unbedingt empfehlen, nun etwas mit der C++ Builder IDE zu "spielen". Nimm ein bestehendes Projekt oder erstelle eigens für deine Tests ein neues, und probiere die verschiedenen Werkzeuge aus, die dir die IDE zur Verfügung stellt. Nur wenn du etwas herumexperimentierst und die unterschiedlichen Optionen ausprobierst, wirst du merken, welche Power in der IDE steckt.
Es kommt einmal der Moment, in dem du dann an die Grenzen der Möglichkeiten dieser Werkzeuge stösst. Wenn dies der Fall ist, ist Kreativität gefragt. Ein Artikel mit einem Auszug aus meiner eigenen kleinen Trickkiste wird demnächst folgen.
Ich möchte an dieser Stelle noch meinen Dank an Jansen aussprechen der sich freundlicher Weise als Lektor betätigt hat. (:

Ich hoffe, dieses Tutorial hat dir etwas geholfen. Viel Erfolg bei der "Käferjagd!" (:<

Zurück zur Übersicht