Hallo Siro,
ANSI-C = Standard-C gibt es erst seit 1990, davor gab es nur die Beschreibung von K&R, welche aber vieles nicht definierte.
Im Prinzip konnte jeder Compilerhersteller machen was er wollte und das ganze C nennen.
Erst mit C90 entstand dann die erste verbindliche Norm.
Manche Compiler haben es ursprünglich so verwendet, in den Standard wurde es erst mit C99 aufgenommen. Wobei es von C++ übernommen wurde.
Die ursprünglichen C-Compiler unter Unix bestanden aus mehreren eigenständigen Programmen, wobei die Ausgab eines Programms die Eingabe für das nächste war:
1. Präprozessor.
Das war eine Stufe, welche eigentlich nur Text finden und ersetzen konnte und keine Ahnung von der C-Syntax hatte. Damit der PP "seine Befehle" finden kann, fangen diese mit # an.
#include <stdio.h>
bewirkt eigentlich nur, dass die Datei "stdio.h" an dieser Stelle in die Ausgabe kopiert wird.
Der PP funktioniert auch mit anderen Sprachen oder man konnte damit auch Bücher erstellen: einfach alle Kapitel mit #include zusammenlinken und dazwischen die Kapitelüberschriften einfügen
2. C-Compiler.
Diese Stufe hat dann aus dem C-Source einen Assembler-Source gemacht.
Normalerweise besteht der CC aus zwei Teilen, dem Frontend, welches aus C eine interne Baumstruktur erstellt und dem Backend, welches aus dem Baum dann den prozessorspezifischen Assembler-Source erzeugt. Das hat den Vorteil, dass für eine neue CPU-Architektur nur das Backend neu geschrieben werden muss, alles davor muss nicht geändert werden.
Das "alte" inline war da recht einfach zu implementieren. Alles was zwischen den Anführungszeichen steht, wird direkt in den Assembler-Source kopiert
Die einfache Registeroptimierung findet im Backend statt, das Aufrollen und umstellen von Schleifen macht man an der Internet Baumstruktur.
3. Optimierer.
Diese Stufe war ursprünglich nur optional und optimierte den Assembler-Source.
4. Assembler.
Schlussendlich wurde dann alles vom Assembler in Maschinencode übersetzt. Dieser Assembler wurde auch alleine für die Assemblerpogrammierung verwendet.
5. Lint.
Das war ein optionaler Pass, zwischen PP und Compiler, welcher auch die falsche Verwendung von Variablen entdeckt hat, also z.B. das Zuweisen eines int an einen char und generelle Unsauberkeiten, welche heute meistens als Warning ausgegeben werden..
Heute ist dies oft in einem einzigen Programm zusammengefasst, aber auch moderne Compiler können noch die Zwischendateien, nach dem PP und den Assembler-Source ausgeben.
"intrinsics.h" ist nur für prozessorspezifische Erweiterungen zuständig.
Es gibt aber auch Bibliotheksspezifische Erweiterungen, welche dann Compilerabhängig sind.
Diese werden dann, sofern sie sich in den definierten Standard-Bibliotheken befinden, auch mit dem _ "markiert".
Oft hat der Sourcelevel-Debugger dann auch seine Probleme, den Source-Code dem Assembler-Code zuzuordnen.
Deshalb produziert man meist auch zwei Versionen, Debug und Retail.
Debug optimiert dann weniger und oft wird auch noch zusätzliche Code eingefügt für z.B. ein Laufzeitüberwachung des Stacks. Oft gibt es dazu auch noch separate Bibliotheken.
Der Code ist natürlich grösser und langsamer und manche Fehler treten genau dann gar nicht aufZusätzlich enthält dann die Datei der Debugversion auch noch die ganzen Symbole für den Debugger.
Lustig wird's auch, wenn die Optimierung Fehler erzeugtDa kann es dann sehr hilfreich sein, den Assembler-Source ansehen zu können, zumal der meist auch mit dem C-Source kommentiert wird.
MfG Peter(TOO)
Lesezeichen