PureC - Die Metamorphose

Enttäuscht reagierte die Programmiererszene auf die Ankündigung Borlands, Turbo C für den Atari nicht mehr zu unterstützen. Vorbei waren die Träume von einem C++-Compiler und weiteren Updates. Doch die Entwickler der ST-Version beschlossen, an dem Compiler in eigener Regie weiterzuarbeiten und ihn von Application Systems Heidelberg unter dem Namen Pure C vertreiben zu lassen.

In diesem Artikel lesen Sie, was das Entwicklerpaket leistet und was sich seit der Version 2.03 von Turbo C getan hat. Sollten Sie mit Turbo C vertraut sein, können Sie den ersten Teil getrost überlesen, da der Compiler nahezu unverändert geblieben ist. Als erstes fällt auf, daß der Compiler nur vollständig mit dem Assembler und Sourcecode-Debugger ausgeliefert wird, was der Profi-Version von Turbo C entspricht. Die überaus bunte Verpackung enthält drei Handbücher und ebenso viele randvolle Disketten.

Die Entwicklungsumgebung

Gewohnt präsentiert sich das Aussehen der Entwicklungsumgebung (Bild 1). Sie enthält einen GEM-Editor, den Compiler und den Linker. Der Editor wurde so programmiert, daß die Benutzer, die an den Macintosh gewöhnt sind, ohne Probleme einsteigen können. So werden Blockbereiche mit der gedrückten Maus selektiert, wobei der Fensterinhalt automatisch nachgescrollt wird, falls die Maus den Fensterbereich verläßt. Ist der Block einmal selektiert, kann er mit den Befehlen Ausschneiden, Kopieren und Einfügen bearbeitet werden. Diese Arbeitsweise erlaubt ein flüssiges Arbeiten. Auch die Entwickler, die zum Beispiel an Tempus gewöhnt sind, finden sich schnell zurecht. Wünschenswert wäre vielleicht eine Option, die das Einbinden eines Lieblingseditors ermöglichte. Ist das Programm geschrieben, kann man es gleich compilieren. Eventuelle Fehler oder Warnungen werden in ein gesondertes Fenster ausgegeben. Dabei bricht der Compiler die Übersetzung nicht bereits beim Auftreten des ersten Fehlers ab, was in den meisten Fällen sehr sinnvoll ist. Ein Doppelklick auf eine Zeile im Fehlerfenster genügt, und der Editor springt an die entsprechende Position im Quelltext. Genauso funktioniert auch das Übersetzen eines Assembler-Quelltextes. Da sich ein C-Programm normalerweise aus mehreren Modulen zusammensetzt, stellt die Shell eine Projekt-Funktion zur Verfügung, die ungefähr dem ‘Make' gleichkommt. Man gibt in einer gesonderten Datei alle Module und Bibliotheken, die übersetzt und gelinkt werden sollen, an und kann diese dann auf einmal compilieren. Auf Wunsch werden nur die geänderten Dateien übersetzt, was bei größeren Projekten auch notwendig ist. Leider kann man aus der Projektdatei nicht ein anderes Programm aufrufen, damit dieses eine Datei precompiliert. Das erschwert zum Beispiel das Einbinden eines objektorientierten Zusatzes erheblich.

Bild 1: Die Entwicklungsoberfläche

Der Compiler

Pure C ist ein ANSI-C-Compiler. Er enthält fast alle vom ANSI-Komitee vorgeschriebenen Erweiterungen zum K&R-C. Es fehlen die völlig überflüssigen Trigraphen, die ‘Locales' (das sind Erweiterungen, die es ermöglichen, nicht nur englische Ausgabeformate für Geld oder Datum zu benutzen) und die Möglichkeit, in einer ‘switch'-Anweisung ‘long'-Werte zu benutzen. Diese drei Einschränkungen sind jedoch minimal. Gravierender ist da schon, daß hexadezimale Escape-Codes drei Ziffern statt korrekterweise zwei erwarten.

Der Compiler gibt eine Vielzahl an unterschiedlichen Fehlermeldungen und Warnungen aus, die das Suchen nach Fehlern erheblich erleichtern. So meckert der Compiler zum Beispiel bei einer Zuweisung innerhalb von ‘if'. Die oft benutzte Technik schleicht sich manchmal unerwünscht an die Stelle eines Vergleichs. Auch so mancher K&R-Konstrukt wird nicht ohne Warnungen verdaut. Da dies beim Compilieren von älteren Quelltexten sehr lästig sein kann, gibt es mehrere Möglichkeiten, die Warnungen zu unterdrücken. Der eine Weg wäre über die Optionen des Compilers, wo man in drei Stufen einstellen kann, ob keine, einige oder alle Warnungen ausgegeben werden. Das ist aber nicht immer sinnvoll, da man auf den Komfort nicht verzichten möchte. Man hat dann die Möglichkeit, innerhalb des Quelltextes bestimmte Warnungen einzeln ein- oder auszuschalten.

Bild 2: Compiler-Optionen

Beim Übersetzen arbeitet der Compiler durchschnittlich schnell, so daß bei großen Projekten schon mal eine Kaffeepause eingelegt werden kann. Ganz anders sieht es mit dem erzeugten Code aus. Pure C erzeugt momentan den schnellsten Code auf dem ST. Interessant ist hierbei, daß der Compiler nahezu keine globalen Optimierungen, wie zum Beispiel das Herausziehen von invarianten Ausdrücken aus einer Schleife, vornimmt, aber trotzdem einen 68000-Code generiert, der seinesgleichen sucht. Dieser kann in hohem Maße beeinflußt werden (Bild 2). Der Compiler verwendet von Haus aus Register für die Parameterübergabe. Diese Option beschleunigt Funktionsaufrufe mit wenigen Argumenten erheblich, kann aber auch ausgeschaltet werden, falls die Funktionen aus anderen Sprachen heraus benutzt werden sollen. Intern wird ein Objektformat verwendet, das nicht mit dem Digital-Research-Standard kompatibel ist. Dies war notwendig, um Bezeichner mit variabler Länge zu ermöglichen. Selbstverständlich gibt es auch die Möglichkeit, DR-Format zu erzeugen. Optional erzeugt der Übersetzer auch 68020- und 68881-Code, so daß auch die Besitzer eines TT zufriedengestellt werden, denn der 68030-Prozessor enthält eine 68020-CPU, die zusätzlich noch mit einer PMMU ausgestattet ist, die aber vom Compiler nicht benötigt wird. Im Listing 1 habe ich eine Funktion mit Pure C übersetzt und disassembliert.

Der Assembler

Der mitgelieferte Assembler unterstützt alle 680x0,6888x und die PMMU 68851. Damit ist er bestens für die Zukunft ausgerüstet. Er verwendet die auf dem ST üblichen Motorola-Direktiven. Zusätzlich zu den Assembler-Befehlen unterstützter viele Pseudo-Mnemonics, wie zum Beispiel ‘export' oder ‘align'. In dieser Hinsicht ist er einer der komplettesten Assembler auf dem Markt. So bietet er neben Makros und den üblichen Schleifenkonstrukten auch besondere Behandlung für Module und ermöglicht die Ausgabe von Crossreference-Listings. Netterweise optimiert er auch einige Adressierungsarten. Auf Wunsch werden DR-Objektdateien erzeugt oder Debugging-Informationen angehängt.

Der Linker

Der Linker von Pure C kann neben dem hauseigenen Objektformat, das zum Debuggen benötigt wird, auch Standard-Objektdateien linken. Häufig benutzte Objektdateien können in Bibliotheken zusammengefaßt und dann automatisch mitgelinkt werden. Schön ist, daß nicht benötigte Symbole, wie zum Beispiel überflüssige Funktionen aus Bibliotheken, auch nicht hinzugefügt werden. Der Linker kann auch spezielle Informationen im Ausgabeformat setzen, die mit neuen Betriebssystemversionen dazugekommen sind. So ist es beispielsweise möglich, das Fastload-Flag zu setzen oder Programme ins TT-RAM zu laden. Negativ ist aufgefallen, daß der Linker sehr zurückhaltend mit Fehlermeldungen ist: Es können subtile Fehler auftreten, wenn Symbole doppelt vorhanden sind. Man muß hier schon das Verbose-Flag (ausführliche Meldungen) setzen, damit überhaupt eine Warnung ausgegeben wird.

Die Bibliotheken

Die Bibliotheken von Pure C sind vollständig, was den Standard angeht. Auch ST-spezifische Funktionen wie das GEM-DOS, das AES oder XBIOS sind korrekt und vollständig enthalten. Darunter verstehe ich auch, daß vom TT neu hinzugekommene Funktionen implementiert sind. Als Bonbon haben die Pure-C-Entwickler die standardisierten Netzwerkfunktionen implementiert. Darüber hinaus sind auch einige Unix- und Pure-C-spezifischen Funktionen nebst dem BGI (Borland Graphics Interface) vorhanden.

Bild 3: Breakpoints, Watches,Modules ...im Debugger Bild 4: Vielfältige Möglichkeiten eines Breakpoints

Der Debugger

Das Feinste an Pure C aber ist sein Debugger. Es ist in der Praxis so, daß fast 50 Prozent der Entwicklungszeit eines großen Projekts für die Entwanzung verbraucht werden. Ohne einen Quelltext-Debugger ist es sehr mühsam, übersetzte Programme zu debuggen, ganz zu schweigen davon, daß man erst Assembler beherrschen muß. Hier setzt der Pure-Debugger an. Hat man sein Programm mit den Debugging-Informationen übersetzt, kann man gleich den Debugger starten. Erstaunlicherweise befindet man sich die ganze Zeit über in GEM. Da das GEM nicht reentrant ist, mußten die Programmierer das gesamte AES neu schreiben, damit der gestreßte Benutzer auch GEM-Programme erfolgreich debuggen kann. Der Aufwand hat sich auf jeden Fall gelohnt, denn der Pure-Debugger ist so einfach zu bedienen, wie man das eigentlich nur von Macintosh- oder PC-Programmierumgebungen gewöhnt ist.

Wie der Name es bereits impliziert, ist es mit einem Quelltext Debugger möglich, ein Programm laufen zu lassen und dabei den C-Quelltext zu inspizieren. Selbstverständlich kann man parallel dazu den übersetzten Code betrachten. Nachdem man ein Programm geladen hat, kann man es ausführen und warten, bis ein Fehler auftritt und der Debugger die fehlerhafte Stelle und den Grund des Fehlers an-zeigt. Da aber Fehler oft keinen Absturz zur Folge haben, muß es auch möglich sein, während der Ausführung in den Debugger zu kommen. Der Pure-Debugger erlaubt hier eine Vielzahl an Varianten: die einfachste ist das Abbrechen der Ausführung durch eine Tastenkombination, weiterhin stehen sehr komplexe Breakpoints zur Verfügung, mit denen es zum Beispiel ein Kinderspiel ist, an bestimmten Stellen im Quelltext oder Programm-Code das Programm anzuhalten. Dabei können auch Abbruchbedingungen angegeben werden, wie die Anzahl der Durchläufe eines Breakpoints, bevor dieser aktiviert wird, oder das Beobachten von Speicherzellen und Ausdrücken. Möchte man die Auswirkungen des Programms genauer unter die Lupe nehmen, kann man sich des Single-Step-Modus bedienen, bei dem immer nur eine einzige Anweisung gleichzeitig ausgeführt wird. Auch hier gibt es zwei Möglichkeiten: ein Funktionsaufruf kann wahlweise als ein einziger Befehl bearbeitet werden, oder aber man springt wirklich in die Funktion hinein, wobei bei Bedarf der passende Quelltext geladen und angezeigt wird. Überhaupt ist das Anzeigen die Stärke des Pure-Debuggers. Will man zum Beispiel den Wert einer Variablen erfahren, reicht ein Doppelklick auf den Bezeichner mit gedrückter Shift-Taste, und schon wird der Inhalt in einem Fenster angezeigt, wobei selbstverständlich die C-Syntax benutzt wird. Somit können auch Strukturen klar dargestellt werden. Verwendet man in seinen Programmen zum Beispiel Listen, reicht ein Doppelklick auf das Strukturelement, das den Nachfolger bezeichnet, und prompt wird ein neues Fenster mit dem Nachfolger selbst geöffnet. Obwohl der Pure-Debugger die Fensteranzahl nicht begrenzt, kann diese Art der Variableninspektion schnell unübersichtlich werden. Deshalb kann man alle Variablen, die man betrachten möchte, in kompakter Form in ein Fenster ausgeben lassen. Der Vorteil dieser Methode ist neben der Übersicht auch die Möglichkeit, beliebig komplexe Ausdrücke betrachten zu können. Betrachten kann man auch den Stack-Inhalt, die CPU-Register, alle Breakpoints und Variablen. Den Speicher kann man im ASCII- und Hex-Modus betrachten oder ihn wahlweise disassemblieren. Zum schnellen Nachladen von Quelltexten benutzt man das Modules-Fenster. Und da viele Programme, die zu debuggen sind, irgendwelche Dateien bearbeiten, kann man sich auch diese im Fenster anzeigen lassen. Sehr fein ist auch die Log-Funktion, die auf Wunsch alle Aktionen in einem Fenster und einer Datei protokolliert. Nicht zu vergessen, daß die ausführliche Hilfestellung auch aus dem Debugger heraus erreichbar ist.

Macht man einzelne Schritte durch das Programm, werden die Fensterinhalte automatisch restauriert. Das ist besonders interessant, wenn man zur Ausführung den sogenannten Animations-Modus verwendet. In diesem Modus werden die Befehle schrittweise automatisch nach einer einstellbaren Zeit ausgeführt.

Der Pure-Debugger ist der derzeit beste Debugger auf dem ST. Er enthält eine Menge an sinnvollen Funktionen, die auch den Anfängern das Leben erleichtern.

Die Tools

Ein gutes Programmierpaket enthält auch eine Menge an hilfreichen Utilities. Auch Pure C macht hier keine Ausnahme. Mitgeliefert werden ein Objektdatei-Disassembler, der Pure C-File-Selector und die OnLine-Hilfe als Accessories und Präprozessor, Compiler, Linker und Assembler als eigenständige Programme, die man aus eigenen Shells heraus verwenden kann. Auf der Diskette befindet sich auch ein Hilfetext-Compiler, der aus einer besonders formatierten Datei eine Hilfedatei produziert, die dann von dem Compiler aus benutzt werden kann, um zum Beispiel eigene Bibliotheksfunktionen zu erläutern.

Bild 5: Alle Variablen können aufgelistet werden.

Die Handbücher

Daserste und gleichzeitig wichtigste Handbuch befaßt sich mit C, speziell natürlich mit Pure C. Nach einer Einführung zur Entwicklungsumgebung geht es gleich mit ersten Programmbeispielen los. Die Sprache C wird meiner Meinung nach sehr gut und übersichtlich dargestellt, so daß auch Programmierer ohne C-Erfahrung nicht überfordert werden. Der Schwierigkeitsgrad steigert sich im Verlauf des Buches und endet mit der syntaktischen Beschreibung von Pure C. Im Handbuch enthalten ist auch eine Kurzbeschreibung aller Bibliotheksfunktionen. Genauere Information muß man aber der OnLine-Hilfe entnehmen.

Auch das Assembler-Handbuch ist für absolute Assembler-Einsteiger geeignet. Es erläutert die wichtigsten Befehle und deren Anwendung in der Praxis, was selbstverständlich auch die notwendigen Betriebssystemaufrufe einschließt. Erklärt wird auch die Parameterübergabe, wenn C-Funktionen aufgerufen werden.

Zum guten Abschluß enthält das Paket ein Debugger-Handbuch. Auch hier zeigt sich deutlich, wie gut Borland die Bücher aufgebaut hat, denn wie die ersten beiden ist auch dieses nahezu unverändert übernommen worden. Es ist durch seinen Aufbau für Neulinge ebenso gut geeignet wie für Erfahrene.

Die Neuigkeiten

Die wahrscheinlich wichtigste Frage eines jeden Turbo-C-Programmierers ist, was er denn für die Update-Gebühr Neues bekommt. Und hier sieht die Sache schon etwas kritischer aus, denn es gibt nicht nur Gutes zu berichten. Doch fangen wir ganz von vorne an.

Was beim ersten Compilieren sofort auffällt, ist die eindeutig schnellere Projekt-Funktion. Bei Turbo C hat es schon mal gedauert, bis der Compiler alle fünfzig Module auf deren Entstehungsdatum geprüft hatte. Der Geschwindigkeit dienlich ist auch eine völlig neue Funktion: das Include- und Object-File-Caching. Im Klartext heißt das, daß automatisch eine Art RAM-Disk für die dauernd benötigten Dateien erstellt wird, mit deren Hilfe Zugriffe auf die Festplatte minimiert werden. Das spart nicht nur wertvolle Zeit, sondern schont auch die Festplatte.

Vielen Erweiterungen ist auch die Hilfe-Funktion unterzogen worden. So ist es zum Beispiel möglich, sich eigene Hilfe-Dateien zu erstellen und sie dann über das Hilfe-Menü zu benutzen. Doch damit nicht genug. Die genialste Neuerung ist meiner Meinung nach das sogenannte Project-Help. Hierbei erzeugt der Compiler während des Übersetzungsvorganges eine Datenbank, die allen global bekannten Bezeichnern ihre Zeilennummer zuordnet. Wenn Sie nun eine Funktion oder Variable selektieren und die Help-Taste drücken, springt der Editor an die Stelle im Quelltext, an der diese definiert wurde. Das lästige Durchsuchen der Dateien nach einem bestimmten Bezeichner entfällt also.

Der Assembler ist von Grund auf neu geschrieben worden. Er ist jetzt um ein Vielfaches schneller als sein Vorgänger. Auch das Handbuch ist erweitert worden. Beim Debugger hat man jetzt die Möglichkeit, die VDI-Funktionen zur Ausgabe zu nutzen, was vor allem Benutzer von Grafikkarten freuen wird. Leider ist auch einiges verschlimmbessert worden. So fehlt ein Referenzhandbuch vollständig. Das schöne Turbo-C-Referenzhandbuch wurde ersatzlos gestrichen. ASH verweist hier auf die OnLine-Hilfe. Auch ein Resource Construction Set fehlt.

Aufgefallen sind mir außerdem ein paar Kinderkrankheiten. Die Cache-Funktion zeigte sich in der zur Messe ausgelieferten Version absturzträchtig. Auch verhielt sich der Computer nach einem Debugging-Durchlauf sehr anfällig gegen Abstürze.

Fazit

Pure C ist insgesamt ein hervorragendes Produkt. Alle Bestandteile sind gut integriert und nahezu fehlerfrei. Für C-Neueinsteiger ist dieser Compiler für DM 398,-konkurrenzlos. Auch die Laser-C-Freunde, die neidisch zu ihren Turbo-C-Kollegen aufblickten, werden sich freuen. ASH bietet ihnen die Möglichkeit eines Updates für DM 198,- für ein völlig neues Produkt. Anders sieht es schon für Turbo-C-Freaks aus. Für ein paar neue Funktionen, nahezu gleiche Handbücher, wobei eines sogar entfallen ist, und das Fehlen eines RCS DM 148,- zu berappen, ist schon ganz schön happig. Hoffentlich kann das der gute Support von ASH ausgleichen, und hoffentlich gibt es endlich mal eine ‘vollständige' C++-Implementation für den ST.

Bezugsadresse
Application Systems Englerstr. 3 W-6900 Heidelberg

/* Dies ist eine Hash-Funktion */

unsigned long hash_pjw(const char *string);

unsigned long
hash_pjw(const char *string)
{
    unsigned    long hash, temp;

    hash = 0;

    for( ; *string != '\0'; string++)
    {
        hash = (hash << 4) + *string;
        if(temp = hash & 0xf0000000L)
        {
            hash ^= temp >> 24; 
            hash ^= temp;
        }
    }
    return(hash);
}

Pure C- Eine Hash-Funktion und ihre Übersetzung

; und die von Pure C übersetzte Routine 

hash_pjw:
        MOVE.L      D3,-(A7)
        MOVEQ.L     #$00,D0
        BRA.B       label3

labell: MOVE.L      D0,D1
        LSL.L       #4,D1
        MOVE.B      (A0),D2
        EXT.W       D2
        EXT.L       D2
        ADD.L       D2,D1
        MOVE.L      D1,D0
        AND.L       #$F0000000,D1
        BEQ.B       label2
        MOVE.L      D1,D2
        MOVEQ.L     #$18,D3
        LSR.L       D3,D2
        EOR.L       D2,D0
        EOR.L       D1,D0
label2: ADDQ.W      #1,A0
label3: MOVE.B      (A0),D1
        BNE.B       label1
        MOVE.L      (A7)+,D3
        RTS

Grischa Ekart
Aus: ST-Computer 10 / 1991, Seite 166

Links

Copyright-Bestimmungen: siehe Über diese Seite