C wurde erstellt, um das Schreiben eines Compilers zu vereinfachen. Es macht eine Menge Sachen, die auf diesem einen Prinzip basieren. Zeiger dienen nur dazu, das Schreiben eines Compilers zu vereinfachen, ebenso wie Header-Dateien. Viele der auf C ++ übertragenen Dinge basieren auf der Kompatibilität mit diesen Funktionen, die implementiert wurden, um das Schreiben des Compilers zu vereinfachen.
Eigentlich ist es eine gute Idee. Als C erstellt wurde, waren C und Unix eine Art Paar. C portierte Unix, Unix lief C. Auf diese Weise konnten sich C und Unix schnell von Plattform zu Plattform verbreiten, während ein auf Assembly basierendes Betriebssystem für die Portierung komplett neu geschrieben werden musste.
Das Konzept, eine Schnittstelle in einer Datei anzugeben und die Implementierung in einer anderen, ist überhaupt keine schlechte Idee, aber das sind keine C-Header-Dateien. Sie sind lediglich eine Möglichkeit, die Anzahl der Durchgänge zu beschränken, die ein Compiler durch Ihren Quellcode ausführen muss, und eine begrenzte Abstraktion des Vertrags zwischen Dateien zu ermöglichen, damit diese kommunizieren können.
Diese Elemente, Zeiger, Header-Dateien usw. bieten keinen wirklichen Vorteil gegenüber einem anderen System. Wenn Sie mehr Aufwand in den Compiler investieren, können Sie ein Referenzobjekt so einfach kompilieren wie einen Zeiger auf genau denselben Objektcode. Dies ist, was C ++ jetzt tut.
C ist eine großartige, einfache Sprache. Es hatte einen sehr begrenzten Funktionsumfang, und Sie konnten ohne großen Aufwand einen Compiler schreiben. Das Portieren ist im Allgemeinen trivial! Ich versuche nicht zu sagen, dass es eine schlechte Sprache ist oder so, es ist nur so, dass Cs Hauptziele bei seiner Erstellung möglicherweise Reste in der Sprache hinterlassen, die jetzt mehr oder weniger unnötig sind, aber aus Kompatibilitätsgründen beibehalten werden.
Es scheint, dass einige Leute nicht wirklich glauben, dass C für Port Unix geschrieben wurde, also hier: ( von )
Die erste Version von UNIX wurde in Assembler-Sprache geschrieben, aber Thompson wollte, dass sie in einer höheren Sprache geschrieben wird.
Thompson versuchte 1971 erstmals, Fortran auf dem PDP-7 einzusetzen, gab jedoch nach dem ersten Tag auf. Dann schrieb er eine sehr einfache Sprache, die er B nannte und die er auf dem PDP-7 in Gang brachte. Es hat funktioniert, aber es gab Probleme. Erstens, weil die Implementierung interpretiert wurde, war sie immer langsam. Zweitens waren die Grundbegriffe von B, die auf der wortorientierten BCPL basierten, für eine byteorientierte Maschine wie die neue PDP-11 einfach nicht richtig.
Ritchie benutzte den PDP-11, um B Typen hinzuzufügen, die für eine Weile NB für "New B" hießen, und begann dann, einen Compiler dafür zu schreiben. "Damit die erste Phase von C wirklich diese beiden Phasen in kurzer Folge waren, wurden zunächst einige Sprachänderungen von B vorgenommen, wobei die Typstruktur hinzugefügt wurde, ohne dass die Syntax zu stark geändert wurde, und der Compiler ausgeführt wurde", sagte Ritchie.
"Die zweite Phase war langsamer", sagte er über das Umschreiben von UNIX in C. Thompson, das im Sommer 1972 begann, aber zwei Probleme hatte: herauszufinden, wie die grundlegenden Co-Routinen ausgeführt werden, dh wie die Steuerung von einem Prozess auf einen umgeschaltet wird Ein weiterer; und die Schwierigkeit, die richtige Datenstruktur zu erhalten, da die ursprüngliche Version von C keine Strukturen hatte.
"Die Kombination der Dinge hat dazu geführt, dass Ken im Sommer aufgegeben hat", sagte Ritchie. "Im Laufe des Jahres habe ich Strukturen hinzugefügt und wahrscheinlich den Compiler-Code etwas besser gemacht - besseren Code - und so haben wir im nächsten Sommer die konzertierten Anstrengungen unternommen und tatsächlich das gesamte Betriebssystem in C wiederhergestellt."
Hier ist ein perfektes Beispiel dafür, was ich meine. Aus den Kommentaren:
Zeiger existieren nur, um das Schreiben eines Compilers zu vereinfachen? Nein. Zeiger existieren, weil sie die einfachste mögliche Abstraktion über die Idee der Indirektion sind. - Adam Rosenfield (vor einer Stunde)
Du hast recht. Um die Indirektion zu implementieren, sind Zeiger die einfachste zu implementierende Abstraktion. In keiner Weise sind sie so einfach zu verstehen oder zu verwenden. Arrays sind viel einfacher.
Das Problem? Um Arrays so effizient wie Zeiger zu implementieren, müssen Sie Ihrem Compiler so ziemlich einen RIESIGEN Codestapel hinzufügen.
Es gibt keinen Grund, warum sie C nicht ohne Zeiger entworfen haben könnten, aber mit Code wie diesem:
int i=0;
while(src[++i])
dest[i]=src[i];
Es wird viel Aufwand (seitens der Compiler) erfordern, die expliziten i + src- und i + dest-Ergänzungen herauszufiltern und denselben Code zu erstellen, den dies ergeben würde:
while(*(dest++) = *(src++))
;
Das Herausrechnen dieser Variablen "i" nach der Tatsache ist HARD. Neue Compiler können das, aber damals war es einfach nicht möglich, und das Betriebssystem, das auf dieser beschissenen Hardware läuft, brauchte solche kleinen Optimierungen.
Jetzt benötigen nur noch wenige Systeme diese Art der Optimierung (ich arbeite auf einer der langsamsten Plattformen - Kabel-Set-Top-Boxen, und die meisten unserer Inhalte befinden sich in Java) und in den seltenen Fällen, in denen Sie sie benötigen, die neuen C-Compiler sollte klug genug sein, um diese Art der Konvertierung selbst durchzuführen.