Jede Option wird im folgenden in der Form
Bedeutung | |||
Name | interaktiv | Typ | Vorgabe |
dargestellt.
Hierbei bezeichnet
Es folgt nun eine genaue Beschreibung der Optionen im einzelnen:
Stapelkontrolle | |||
StackChk | s | stapelbar | TRUE |
Das Betriebssystem kontrolliert nicht, ob ein Prozess den ihm zugewiesenen Stapelbereich überschreitet. Ist dies der Fall, stellt sich meist ein unerklärlicher Laufzeitfehler ein, dessen Ursache kaum feststellbar ist. Der Compiler generiert Code zur Überprüfung des Stackbereichs. Diese Überprüfung muss zu Beginn jeder Prozedur, sowie manchmal auch innerhalb der Prozedur durchgeführt werden. Dies vergrössert den Code und verlangsamt das Programm. Werden keine Prozeduren rekursiv aufgerufen, und ist sonst ein Stacküberlauf unwahrscheinlich, kann die Option ausgeschaltet werden.
Die Option wird zu Beginn jeder Prozedur eingefroren und am Ende wieder freigegeben. Der Änderbarkeitsbereich ist identisch mit dem der bereichsbezogenen Optionen.
Bereichskontrolle | |||
RangeChk | r | stapelbar | TRUE |
Wird auf einen Unterbereich (``subrange`` wie [0..31]
oder
ein Feld wie a[3]
) zugegriffen, generiert der Compiler Code,
um die Einhaltung der Bereichsgrenzen zu überprüfen.
Unter- oder Überschreiten
eines solchen Bereichs bricht das Programm mit einem Laufzeitfehler ab.
Ist das
Programm vorsichtig ausgetestet (und nur dann), kann die Kontrolle
mit (*$ RangeChk:=FALSE *)
ausgeschaltet werden, um etwas
Geschwindigkeit zu gewinnen.
Aber auch während der Compilation hat diese Option eine Wirkung. Der Compiler kann konstante Werte bereits zu dieser Zeit auf die Einhaltung von Bereichsgrenzen überprüfen.
Über-, Unterlaufskontrolle | |||
OverflowChk | v | stapelbar | TRUE |
Die interne Zahlenrepräsentation kennt keine zu grossen oder zu kleinen Zahlen. Jede Über- oder Unterschreitung bei der Berechnung von Ausdrücken lässt sich jedoch durch das Testen eines speziellen Prozessor-Registers (CCR, ``condition code register``) feststellen. Der Compiler generiert Überprüfungscode, der im Fehlerfall zur Laufzeit das Programm abbricht. Ist das Programm vorsichtig ausgetestet, kann diese Kontrolle durch
(*$ OverflowChk:=FALSE *)
ausgeschaltet werden.
Zeigerkontrolle | |||
NilChk | n | stapelbar | TRUE |
Die Verwendung nicht-initialisierter Zeiger kann bei ihrer Dereferenzierung zu unvorhersehbaren Ergebnissen und Programm-Abstürzen führen. Der Compiler erzeugt Code, der zur Laufzeit testet, ob ein Zeiger auf die Adresse 0 (NIL) verweist. Dadurch kann zur Laufzeit das Programm abgebrochen werden. Ist das Programm vorsichtig ausgetestet, kann diese Überprüfung durch
(*$ NilChk:=FALSE *)
ausgeschaltet werden.
Nullinitialisierung | |||
EntryClear | e | stapelbar | TRUE |
Da der Anfangswert einer lokalen Variablen nicht bestimmt ist, werden diese explizit auf Null gesetzt. Somit kann die Zeigerkontrolle richtig gut greifen. Soll diese Operation nicht durchgeführt werden, muss die Option mit
(*$ EntryClear:=FALSE *)
ausgeschaltet werden.
Fallüberprüfung | |||
CaseChk | c | stapelbar | TRUE |
Wenn innerhalb einer CASE-Anweisung der aktuelle Wert ausserhalb aller angegebenen Teilbereiche liegt und kein ELSE-Teil angegeben wurde, wird das Programm mit einem Laufzeitfehler abgebrochen. Für diese Überprüfung wird dazu vom Compiler Code generiert, der durch die Option
(*$ CaseChk:=FALSE *)
vermieden wird. Die Wirkung
ist identisch mit der Angabe eines leeren ELSE-Teiles.
Funktionsrückgabe | |||
ReturnChk | f | stapelbar | TRUE |
Am Ende jeder Funktionsprozedur generiert der Compiler Code, der im Falle einer fehlenden RETURN-Anweisung ausgeführt wird und das Programm mit einem Laufzeitfehler abbricht. Ist bei einer Funktionsprozedur die ordnungsgemässe Beendigung garantiert (und nur dann), kann die Generierung des Überprüfungscodes mit
(*$ ReturnChk:=FALSE *)
abgeschaltet werden.
Ein-/Ausgangs-Code | |||
EntryExitCode | n.a. | bereichsbezogen | TRUE |
Jede Prozedur führt zu Beginn einen speziellen Code aus, der eine Stapelüberprüfung vornimmt, Platz für die lokalen Variablen auf dem Stapel alloziert, den dynamischen Link erstellt, die innerhalb der Prozedur benutzten Register auf dem Stack ablegt, und bei Bedarf die offenen Feldparameter auf den Stack kopiert. Am Ende der Prozedur werden (bei Funktionsprozeduren) der Code zur Rückgabekontrolle generiert, die zu Beginn geretteten Register vom Stapel geholt, die lokalen Variablen und die Parameter abgebaut und eine Rückkehranweisung ausgeführt.
Diese beiden Codeteile werden nach
(*$ EntryExitCode:=FALSE *)
nicht erzeugt. Dies wird vor allem bei reinen Assembler-Prozeduren, bei
denen der Programmierer für alle oben genannten Aktionen selbst
verantwortlich ist, oder bei Prozeduren, die lediglich als
,,Verpackung`` für Daten dienen, benötigt.
Offene Felder | |||
CopyDyn | n.a. | bereichsbezogen | TRUE |
Eine Prozedur, die offene Feldparameter als Werteparameter besitzt,
muss diese zu Beginn auf den Stack kopieren, damit die übergebene
Variable oder Konstante nicht verändert werden kann (siehe auch
5.5.5, Seite ). Für die
Herstellung der Kopie muss Code erzeugt werden. Falls der Parameter
innerhalb der Prozedur nicht verändert wird, kann das
Kopieren mit der Option
(*$ CopyDyn:=FALSE *)
unterbunden
werden, was Code und Laufzeit spart. Danach wird der Parameter wie
ein VAR-Parameter behandelt, behält aber den Vorteil, dass auch
Konstanten übergeben werden können.
Parameter-Abbau | |||
ParDealloc | n.a. | bereichsbezogen | TRUE |
In dealloziert jede Prozedur ihre Parameter selbst wieder, da sie aus der Vereinbarung genau weiss, mit wievielen Parametern sie aufgerufen wurde. In der Sprache C werden die Parameter vom Aufrufer dealloziert, da nur dieser weiss, wieviele Parameter er übergeben hat. Einige Betriebssystem-Prozeduren benötigen eine Prozedur als Parameter. Diese dürfen ihre Parameter dann allerdings nicht selbst abbauen, da dies ja die aufrufende Prozedur des Betriebssystems tut. Der Parameter-Abbau kann mit
(*$ ParDealloc:=FALSE*)
unterbunden werden.
Sichere und lade A4 | |||
LoadA4 | n.a. | bereichsbezogen | FALSE |
Normalerweise wird das Register A4 von unserem
-Laufzeitsystem zu Beginn des
Programmes einmal mit der Basis der globalen -Variablen initialisiert
und während des Programmlaufs nicht verändert.
Falls jedoch -Prozeduren
vom Betriebssystem aufgerufen werden,
z.B. Interrupt-Handler, ist A4 zu Beginn der Prozedur
,,zerstört`` und muss neu ,,beschafft`` werden. Näheres steht in
6.2.2, Seite . Dort befindet sich auch ein ausführliches
Beispiel für den Nutzen dieser Option. Die Angabe
(*$ LoadA4:=TRUE *)
gilt für die nächste Prozedur und bewirkt, dass Register A4 mit den anderen
Registern auf den Stack gerettet und mit der Basis der -Variablen
(,,_LinkerDB``) geladen wird. Am Ende der Prozedur wird A4
wiederhergestellt.
Damit ist ein Programm nicht mehr
residentfähig, da jeder Aufruf eines residentfähigen
Programms seine eigenen globalen Daten bekommt. Sie in
diesem Fall die folgende Option!
Sichere A4 | |||
SaveA4 | n.a. | bereichsbezogen | FALSE |
Diese Option ist fast identisch mit LoadA4. Die Angabe
(*$ SaveA4:=TRUE *)
gilt für die nächste Prozedur und bewirkt, dass das Register A4
mit den anderen
Registern auf den Stack gerettet und am Prozedurende wiederhergestellt wird.
Hier wird also - im Gegensatz zu LoadA4 -- das Register nicht explizit
mit einem Wert geladen, sondern nur gerettet. Es muss nun innerhalb der
Prozedur vom Programmierer ,,per Hand`` gesetzt werden. Dadurch kann
die Residentfähigkeit eines Programmes erhalten werden. Auch hier
findet sich ein Beispiel im Abschnitt 6.2.2.
Implementation | |||
Implementation | n.a. | pro Modul | TRUE |
Zu jeder Symboldatei erwartet der Linker auch eine Objektdatei. Besteht jedoch die Definition nur aus Typen- und Konstanten-Vereinbarungen oder der Deklaration absoluter oder externer Variablen und ist kein Code beim Import dieses Moduls auszuführen -- vom Compiler nur beim Implementations-Modul feststellbar --, erübrigt sich eine Objektdatei. In diesem Fall ist vor dem ersten Import oder der ersten Deklaration die Compiler-Anweisung
(*$ Implementation:=FALSE *)
zu schreiben. Dies spart also des Schreiben eines ,,leeren``
ImplementationsModuls und die Ausführung unnützen Codes. Ein
wenig Code muss sonst auch bei leeren Moduln erzeugt und durchlaufen werden.
Bezeichnerkontrolle | |||
NameChk | n.a. | pro Modul | TRUE |
In einer Symboldatei werden alle Bezeichner der Prozedurparameter abgelegt und deren Übereinstimmung in der Implementation überprüft. Stimmen die Namen nicht überein, erfolgt eine Fehlermeldung. Sollen die Bezeichner nicht vermerkt werden, kann in einem Definitionsmodul das Ablegen der Bezeichner mit
(*$ NameChk:=FALSE *)
unterbunden werden. Der Nutzen liegt in kleineren und schneller
einzulesenden Symboldateien. Sollen nur die abgelegten Bezeichner nicht
überprüft werden, kann die Option zu Beginn des Implementationsmoduls
angegeben werden.
Langwortgrenzen | |||
LongAlign | l | stapelbar | TRUE |
Normalerweise werden globale Variablen, die mehr als ein Byte belegen, auf Langwortgrenzen abgelegt. Dies ist manchmal zwingend notwendig (z.B. DosD.FileInfoBlock), lässt aber auch die Programme auf Prozessoren mit 32-Bit Datenbus -- 68020 und höher -- schneller laufen. Falls dies nicht nötig ist, kann durch die Angabe
(*$ LongAlign:=FALSE *)
eine dichteres Aufeinanderfolgen der Variablen erreicht werden. Sie
liegen dann auf Wortgrenzen. Näheres ist im Abschnitt 5.5.7,
Seite
Zeiger vergessen | |||
Volatile | h | stapelbar | TRUE |
Falls diese Option durch
(*$ Volatile:=FALSE *)
auf FALSE gesetzt wird, versucht der Compiler, möglichst viele Zeiger
in Adressregistern zu halten und wiederzubenutzen, was enorm Code sparen
kann. Näheres kann man in Abschnitt 6.2.8,
Seite
StackParameter | |||
StackParms | z | stapelbar | TRUE |
Normalerweise müssen Parameter, welche die Register D0 oder D1 belegen, bis zum endgültigen Prozeduraufruf zunächst auf dem Stack zwischengelagert werden, weil sie sonst durch andere Operationen zerstört werden könnten. Durch
(*$ StackParms:=FALSE *)
wird erreicht, dass sie gleich, ohne Umweg über den Stack, in diesen
Registern abgelegt werden, was Code und Laufzeit spart. Hierbei können
jedoch Probleme auftreten; lesen Sie bitte Abschnitt 6.2.5,
Seite
Zeichenketten-Konstanten | |||
CStrings | n.a. | stapelbar | TRUE |
Da die Sonderbehandlung des Zeichens ,,\
``
in Zeichenketten-Konstanten
(siehe 5.1.6, Seite ) zu Inkompatibilitäten
führen kann, kann durch
(*$ CStrings:=FALSE *)
auf die normale Bedeutung dieses Zeichens umgeschaltet werden.
Entwickler-Option | |||
Joker | j | stapelbar | TRUE |
Diese Option ist den Entwicklern des -Systems zu Testzwecken vorbehalten. Sie kann in jeder neuen Revision des Compilers eine andere Bedeutung haben und sollte deshalb vom Anwender keinesfalls eingesetzt werden!
-Modell | |||
LargeVars | y | pro Modul | TRUE |
Um die Anzahl und Grösse der globalen Variablen eines Moduls nicht einzuschränken, wird jedes Modul standardmässig im -Modell kompiliert. Durch die Angabe
(*$ LargeVars:=FALSE *)
wird erreicht, dass es im -Modell kompiliert wird, also
alle globalen Variablen dieses Moduls sind, was die Codegrösse
verringert, das Programm beschleunigt und vor allem Bedingung
für residentfähige Programme ist.
Was hierbei zu beachten ist, wird in Abschnitt 5.1.12,
Seite
Daten in Chip | |||
ChipDATA | n.a. | pro Modul | FALSE |
Mit ist es möglich, globale Variablen mit einem vorinitialisierten Wert zu versehen:
VAR i:=INTEGER2;Diese Option entspricht in der Wirkungsweise der Option ChipCODE. Mit der Option ChipDATA werden die so vorinititialisierten globalen Variablen (5.1.8) im Chip-Memory abgelegt.
Daten müssen dann im Chip-Memory liegen, wenn die Custom Chips des Amigas darauf zugreifen müssen.
Daten in Chip | |||
ChipBSS | n.a. | pro Modul | FALSE |
Normalerweise wird für die nicht vorinitialisierten globalen Variablen eines Moduls kein bestimmter Speichertyp verlangt, das Betriebssystem vergibt den bestmöglichen. Durch die Anweisung
(*$ ChipBSS:=TRUE *)
werden die globalen Daten des gesamten Moduls im Chip-Memory angelegt.
Der Einsatz dieser Option unterliegt den gleichen Einschränkungen wie die Option ChipDATA.
Code in Chip | |||
ChipCODE | n.a. | pro Modul | FALSE |
Hier gilt das gleiche wie unter ChipDATA und ChipBSS gesagte. Durch die Anweisung
(*$ ChipCODE:=TRUE *)
wird der gesamte Code- und Konstanten-Bereich des Moduls im
Chip-Memory abgelegt.
Zielprozessor | |||
m68000...m68881 | 0...8 | pro Modul | 0 |
Diese Optionen sind ausschliesslich von der Kommandozeile durch die Ziffern 0, 1, 2, 3, 4 und 8 zu setzen. Sie dienen dazu, den Zielprozessor für den erzeugten Code festzulegen und so den optimalen Code zu erzeugen. Der Zielprozessor muss dabei nicht unbedingt identisch mit dem Prozessor des eigenen Amigas sein.
Standardeinstellung ist ,,0``, d.h. der Compiler generiert Code, der auf allen Prozessoren der MC68000er-Familie lauffähig ist.
Bei der bedingten Kompilierung sind die in der Tabelle angegebenen
Namen in IF-Abfragen erlaubt. Dabei ist zu beachten, dass all diese
Optionen in gegenseitiger Abhängigkeit stehen, wie in Tabelle
2.5 zu sehen und unter 5.1.11,
Seite beschrieben ist.