Für die Version 2.0 von Laser C gibt es einen Source Level Debugger mit Namen LaserDB. Da sich an Laser C selbst nicht allzuviel geändert hat, gehe ich in diesem Artikel nur auf den LaserDB ein.
Was ein Debugger ist, brauche ich ja nicht erst zu erklären - oder doch? Na gut! Ein Debugger ist ein Werkzeug mit dem man Fehler in anderen Programmen lokalisieren kann, um sie dann zu beseitigen (Wer hat da gesagt, ein Kopierschutz sei auch ein Fehler?!). Man kann sich also den Code eines Programms ansehen, den Zustand der Prozessorregister ausgeben lassen, Unterbrechungspunkte setzen, Speicherbereiche ansehen und ein Programm Schritt für Schritt abarbeiten. Das sind so die wichtigsten Grundfunktionen der meisten Debugger. Die Voraussetzung, um mit so einem Debugger zu arbeiten, ist jedoch Assembler zu beherrschen. Das ist nämlich in der Regel das einzige, was ein normaler Debugger kann. Da der Trend beim Programmieren weg vom Assembler und hm zu den Hochsprachen (C, Pascal, Modula) geht, werden Programmierer mit guten Assembler Kenntnissen immer knapper. Darauf reagieren die Hersteller von Programmentwicklungssystemen mit einer neuen Generation von Debuggern, die es erlauben, direkt mit dem Quelltext der Hochsprache, in der ein Programm geschrieben ist, zu debuggen. Aus der Sicht der Softwareentwickler lohnt sich die Investition für einen Source Level Debugger ganz bestimmt, denn er hilft, die Zeiten, die bei der Fehlersuche anfallen, drastisch zu reduzieren, und Zeit ist schließlich Geld.
Genug des Vorgeplänkels und hinein in die Funktionen von LaserDB. Um Programme im Quellcode zu debuggen, müssen beim Übersetzen und Linken Informationen für den Debugger erzeugt werden. Dies geschieht entweder durch Anklicken einer Box in der Compiler- bzw. Linker-Dialogbox oder durch Setzen des -Z-Flags in der Kommandozeile. Ein Programm kann zwar aus mehreren Quelltextdateien zusammengesetzt sein, es müssen aber nicht alle mit der Debug-Option übersetzt werden. Man kann also ausgetestete und fehlerfreie Module normal übersetzen und spart den Speicherplatz, den die Quelltexte dafür im Debugger belegen würden. Diese Methode ist insbesondere deshalb sinnvoll, weil LaserDB immer alle Quelltexte, die für ein Programm zur Verfügung stehen, lädt und aneinanderhängt. Der Quelltext sieht also immer so aus, als würde er in einer einzigen langen Datei stehen. Diese Lösung ist bei umfangreichen Programmen sehr unübersichtlich. Ansonsten ist die Arbeit mit LaserDB ein Vergnügen. Dazu trägt besonders die leichte Bedienbarkeit bei. Die ersten Gehversuche waren auch ohne Handbuch (real programmers don't read manuals) ganz erfolgreich. Auch wenn aus technischen Gründen GEM keine Verwendung fand, gibt es Fenster und so etwas wie eine Menüleiste. Von der fallen allerdings keine Menüs herunter, sondern wenn man mit der Maus auf einen Menütitel klickt, wird entweder eine neue Ebene angezeigt, oder, wenn man schon auf der untersten Menüebene angelangt ist, die entsprechende Funktion ausgeführt. Das ganze kann auch über die Tastatur gesteuert werden, indem man den großgeschriebenen Buchstaben (normal den ersten) eines Menütitels drückt. Das P-System läßt grüßen. Zusätzlich sind die wichtigsten Kommandos auch direkt durch Tastenkombinationen mit Control erreichbar.
LaserDB teilt den Bildschirm in verschiedene Bereiche. Es gibt, wie schon erwähnt, eine Menüleiste am oberen Bildschirmrand. Darunter befinden sich untereinander drei Fenster. Als erstes ein Fenster mit dem Titel Watches, in dem man sich den Inhalt von Variablen ständig anzeigen lassen kann. Darunter der Quelltext, der den größten Teil des Schirms einnimmt. Im untersten Fenster kann man sich Expressions, also Ausdrücke anzeigen lassen. Wer das Assemblern nicht lassen kann, hat zusätzlich noch die Möglichkeit, sich den Inhalt der Prozessorregister oder des Stacks anzeigen zu lassen. Das Fenster für die Register bzw. den Stack nimmt dann einen schmalen Streifen am rechten Rand ein.
Es gibt verschiedene Möglichkeiten, ein Programm abzuarbeiten. Läßt man das Programm mit dem Go-Kommando loslaufen, wird es entweder an einem Unterbrechungspunkt angehalten oder durch Drücken der Tastenkombination Alternate+Help. Wenn man an einer kritischen Stelle angelangt ist, kann man mit dem Next-Kommando die nächste Zeile ausführen. Next behandelt auch Funktionsaufrufe als einzelne Zeile. Um in eine Funktion hineinzuverzweigen, gibt es das Step-Kommando. Wenn man von der Funktion, in die man hineingesteppt ist, genug hat, kommt man mit dem Return-Kommando wieder zurück an die Stelle des Aufrufs, wobei die Funktion selbstverständlich vorher bis zum Ende ausgeführt wird.
Unterbrechungspunkte, auch Breakpoints genannt, kann man setzen, indem man mit der Maus auf die gewünschte Zeile im Quelltext klickt. Links von der Zeile wird dann eine Marke gesetzt (siehe Bild). Wenn das Programm an einem der Unterbrechungspunkte ankommt, wird die Ausführung angehalten und in den Debugger verzweigt. Breakpoints können auch mit einer Bedingung versehen werden. Das Programm wird nur dann angehalten, wenn die Bedingung erfüllt ist. Das ist praktisch, um Fehler zu finden, die in einer Schleife erst nach 857 Durchläufen auftreten. Eine der schönsten Funktionen eines Source Level Debuggers ist die Möglichkeit, strukturierte Variablen im Klartext anzeigen zu lassen. LaserDB zeigt auch ein Array aus geschachtelten Strukturen fehlerfrei an. Über die Formatierung läßt sich allerdings streiten. In dem Fenster mit den Expressions ist ein Beispiel zu sehen. Es ist zwar platzsparend, die Strukturelemente nebeneinander anzuordnen, aber übersichtlich ist das keinesfalls. Hier wäre es praktisch, wenn es zwei Modi gäbe, um Strukturen wahlweise nebeneinander oder untereinander anzuzeigen.
Besonders gut hat mir die Ausgabe von Ausdrücken gefallen. Sie können mit den gleichen Formatierungszeichen wie bei printf() formatiert werden und dürfen die gewohnten C-Operatoren enthalten. Natürlich entsprechen auch die Prioritäten den C-Konventionen. Um die Arbeit noch komfortabler zu gestalten, kann man beliebige Ausdrücke auf die Funktionstasten legen und von dort aus jederzeit bequem abrufen.
Zwei weitere praktische Kommandos sind Calls und Journal. Mit Calls kann man sich die Funktionsaufrufe mit den dazugehörigen Parametern ausgeben lassen. Journal zeigt die letzten 100(!) abgearbeiteten Programmzeilen an.
Abgerundet wird die Benutzerfreundlichkeit dadurch, daß am Ende jeder Sitzung alle Einstellungen abgespeichert werden. Wenn man den Debugger das nächste Mal startet, findet man alles wieder so vor, wie man es gerne haben möchte. Daran sollten sich andere Programme ein Beispiel nehmen.
Fast hätte ich vergessen zu erwähnen, daß man mit LaserDB auch in Assembler arbeiten kann. Natürlich kann man damit auch fremde Programme debuggen. Falls Symbole vorhanden sind, werden sie selbstverständlich verwendet. Man kann auch jederzeit vom Quelltext in den Assemblermodus umschalten.
Das ist nützlich, um den Compiler zu kontrollieren. Oft kann man durch einfache Änderungen im C-Quelltext den Compiler dazu bewegen, viel besseren Code zu erzeugen. Experimentieren Sie doch einmal mit dem Wörtchen register vor Variablen, die häufig benutzt werden besonders bei Zeigern auf Strukturen. Oder schreiben Sie unsigned vor int- oder long-Variablen, die nur positive Werte annehmen. Der Compiler wird es Ihnen durch kompakteren und schnelleren Code danken.
Wie ich vorher schon kurz erwähnte, bin ich kein großer Handbuchleser. Bei LaserDB bin ich (wenn auch mit Verzögerung) schwach geworden. Von den 40 Seiten des deutschen Handbuchs habe ich 30 gelesen und kann das jedem nur wärmstens empfehlen. Es ist sachlich und leicht verständlich geschrieben. Für Anfänger gibt es sogar ein Beispiel für eine Arbeitssitzung, in dem jeder einzelne Schritt erläutert wird. Auch ein Index fehlt nicht.
Wenn Sie dieses Heft in den Händen halten, sollte Laser 2.0 zusammen mit LaserDB verfügbar sein. Die neue Version kostet mit LaserDB ca. 100 DM mehr. Eine Investition, die sich auf jeden Fall lohnt.
JL
Bezugsadresse
Application Systems /// Heidelberg
Englerstr. 3
6900 Heidelberg