C ist eine der am häufigsten verwendeten Sprachen der Welt. Es macht einen großen Teil des vorhandenen Codes aus und wird weiterhin für eine große Menge neuen Codes verwendet. Es ist bei seinen Benutzern sehr beliebt, es ist so weit verbreitet, dass die Fähigkeit, C auszuführen, für viele die informelle Definition einer Plattform ist , und es wird von seinen Fans als "kleine" Sprache mit relativ sauberen Funktionen gelobt.
Wo sind also alle Compiler?
Auf dem Desktop gibt es (realistisch gesehen) zwei : GCC und Clang. Wenn Sie ein paar Sekunden darüber nachdenken, werden Sie sich wahrscheinlich daran erinnern, dass Intel ebenfalls existiert. Es gibt eine Handvoll anderer, die für den Durchschnittsbürger viel zu dunkel sind, um sie zu nennen, und die sich im Allgemeinen nicht die Mühe machen, eine neuere Sprachversion (oder oft sogar eine genau definierte Sprachuntermenge, nur "eine Untermenge") zu unterstützen. Die Hälfte der Mitglieder dieser Liste sind historische Fußnoten. Die meisten anderen sind sehr spezialisiert und implementieren immer noch nicht die vollständige Sprache. Sehr wenige scheinen Open Source zu sein.
Scheme and Forth - andere kleine Sprachen, die von ihren Fans geliebt werden - haben wahrscheinlich mehr Compiler als tatsächliche Benutzer. Sogar etwas wie SML hat "ernstere" Implementierungen zur Auswahl als C. Während die Ankündigung eines neuen (unvollendeten) C-Compilers, der auf Verifikation abzielt, tatsächlich einige ziemlich negative Reaktionen hervorruft und erfahrene Implementierungen Schwierigkeiten haben, genügend Mitwirkende zu bekommen, um überhaupt aufzuholen C99.
Warum? Ist die Implementierung von C so schwierig? Es ist nicht C ++. Haben Benutzer einfach eine sehr verzerrte Vorstellung davon, in welche Komplexitätsgruppe sie fallen (dh, dass sie tatsächlich näher an C ++ als an Schema liegt)?
Antworten:
Heutzutage benötigen Sie einen echten C-Compiler, um einen optimierenden Compiler zu sein , insbesondere, weil C keine hardwarenahe Sprache mehr ist, da aktuelle Prozessoren unglaublich komplex sind ( außer Betrieb , Pipeline , superskalar , mit komplexen Caches und TLBs) . daher wird eine Befehlsplanung benötigt , etc ...). Die heutigen x86-Prozessoren sind keine i386-Prozessoren des vorigen Jahrhunderts, auch wenn beide in der Lage sind, denselben Computercode auszuführen. Siehe, das C ist kein Low-Level- Papier (Ihr Computer ist kein schnelles PDP-11) von David Chisnall.
Nur wenige Leute verwenden naive, nicht optimierende C-Compiler wie tinycc oder nwcc , da sie Code erzeugen, der um ein Vielfaches langsamer ist als der, den optimierende Compiler liefern können.
Das Codieren eines optimierenden Compilers ist schwierig. Beachten Sie, dass sowohl GCC als auch Clang eine "quellensprachenneutrale" Codedarstellung optimieren (Gimple für GCC, LLVM für Clang). Die Komplexität eines guten C-Compilers befindet sich nicht in der Analysephase!
Insbesondere ist das Erstellen eines C ++ - Compilers nicht viel schwieriger als das Erstellen eines C-Compilers: Das Parsen von C ++ und das Umwandeln in eine interne Codedarstellung ist komplex (da die C ++ - Spezifikation komplex ist), aber gut verstanden, aber die Optimierungsteile sind noch viel komplexer Komplex (innerhalb von GCC: Die Middle-End-Optimierungen, quellensprachlich und zielprozessorneutral, bilden die Mehrheit des Compilers, wobei der Rest zwischen Frontends für mehrere Sprachen und Backends für mehrere Prozessoren ausgeglichen wird ). Daher sind die meisten optimierenden C-Compiler auch in der Lage, einige andere Sprachen wie C ++, Fortran, D, ... zu kompilieren. Die C ++ - spezifischen Teile von GCC machen etwa 20% des Compilers aus.
Außerdem wird C (oder C ++) so häufig verwendet, dass die Benutzer erwarten, dass ihr Code kompilierbar ist, auch wenn er nicht genau den offiziellen Standards entspricht, die die Semantik der Sprache nicht genau genug definieren (sodass jeder Compiler möglicherweise seine eigene Interpretation hat) davon). Schauen Sie sich auch den von CompCert bewährten C-Compiler und den statischen Analysator Frama-C an , die sich um eine formalere Semantik von C kümmern .
Und Optimierungen sind ein Long-Tail- Phänomen: Ein paar einfache Optimierungen zu implementieren ist einfach, macht einen Compiler jedoch nicht wettbewerbsfähig! Sie müssen viele verschiedene Optimierungen implementieren und sie geschickt organisieren und kombinieren, um einen echten Compiler zu erhalten, der wettbewerbsfähig ist. Mit anderen Worten, ein Compiler zur Optimierung der Realität muss eine komplexe Software sein. Übrigens haben sowohl GCC als auch Clang / LLVM mehrere interne spezialisierte C / C ++ - Codegeneratoren. Und beide sind riesige Bestien (mehrere Millionen Quellcodezeilen, mit einer Wachstumsrate von mehreren Prozent pro Jahr) mit einer großen Entwicklergemeinschaft (einige hundert Personen, die meistens in Vollzeit oder mindestens in Halbzeit arbeiten).
Beachten Sie, dass es (meines Wissens nach) keinen Multithread-C-Compiler gibt, auch wenn einige Teile eines Compilers parallel ausgeführt werden könnten (z. B. prozedurale Optimierung, Registerzuweisung, Befehlsplanung ...). Und paralleles Bauen mit
make -j
ist nicht immer ausreichend (besonders bei LTO ).Außerdem ist es schwierig, einen C-Compiler von Grund auf neu zu programmieren, und ein solcher Aufwand muss mehrere Jahre dauern. Schließlich sind die meisten C- oder C ++ - Compiler heute freie Software (es gibt keinen Markt mehr für neue proprietäre Compiler, die von Startups verkauft werden) oder zumindest monopolistische Produkte (wie Microsoft Visual C ++ ), und für Compiler ist eine freie Software fast erforderlich ( weil sie Beiträge von vielen verschiedenen Organisationen benötigen).
Ich würde mich sehr freuen, wenn ich finanzielle Unterstützung für die Arbeit an einem C-Compiler von Grund auf als freie Software erhalten könnte, aber ich bin nicht naiv genug, um zu glauben, dass dies heute möglich ist!
quelle
(there is no more a market for proprietary compilers
Sagen Sie das dem Visual Studio-Team ...Ich möchte Ihre zugrunde liegende Annahme, dass es nur eine kleine Anzahl von C-Implementierungen gibt, in Abrede stellen.
Ich kenne C nicht einmal, ich benutze C nicht, ich bin kein Mitglied der C-Community, und dennoch kenne ich weit mehr als die wenigen Compiler, die Sie erwähnt haben.
In erster Linie gibt es den Compiler, der wahrscheinlich sowohl GCC als auch Clang auf dem Desktop völlig in den Schatten stellt: Microsoft Visual C. Trotz der Fortschritte, die sowohl OSX als auch Linux auf dem Desktop gemacht haben, und des Marktanteils, den iOS und Android "gestohlen" haben Windows ist nach wie vor das dominierende Desktop-Betriebssystem, und die meisten Windows-Desktop-C-Programme werden wahrscheinlich mit Microsoft-Tools kompiliert.
Traditionell hatte jeder Hersteller von Betriebssystemen und Chips eigene Compiler. Microsoft als Betriebssystemanbieter verfügt über Microsoft Visual C. IBM als Betriebssystemanbieter und als Chipanbieter verfügt über XLC (dies ist der Standardsystemcompiler für AIX und der Compiler, mit dem sowohl AIX als auch i / OS kompiliert werden). . Intel hat einen eigenen Compiler. Sun / Oracle hat einen eigenen Compiler in Sun Studio.
Hinzu kommen die leistungsstarken Compiler-Anbieter PathScale und The Portland Group, deren Compiler (und OpenMP-Bibliotheken) für die Zahlenverarbeitung verwendet werden.
Digital Mars ist auch noch im Geschäft. Ich glaube, Walter Bright hat die einzigartige Auszeichnung, der einzige Mensch auf dem Planeten zu sein, der es geschafft hat, einen C ++ - Compiler in Produktionsqualität (meistens) selbst zu erstellen.
Last but not least haben wir alle proprietären Compiler für eingebettete Mikrocontroller. Im IIRC werden jedes Jahr mehr Mikrocontroller verkauft als Desktop-, Mobil-, Server-, Workstation- und Mainframe-CPUs in der gesamten Computergeschichte. Das sind also definitiv keine Nischenprodukte.
Eine Auszeichnung geht an TruffleC , einen C - Interpreter (!), Der auf der JVM (!) Läuft und mit dem Truffle AST - Interpreter - Framework geschrieben wurde, das nur 7% langsamer ist als GCC und Clang (je nachdem, welches auf einem bestimmten Benchmark am schnellsten ist) Computersprachen-Benchmark-Spiel und schneller als beide auf Mikrobenchmarks. Mit TruffleC konnte das Truffle-Team seine Version von JRuby + Truffle dazu bringen, Ruby C-Erweiterungen schneller als die eigentliche C-Ruby-Implementierung auszuführen!
Das sind also 6 Implementierungen zusätzlich zu den von Ihnen aufgelisteten, die ich auf den ersten Blick benennen kann, ohne überhaupt etwas über C zu wissen.
quelle
Wie viele Compiler benötigen Sie?
Wenn sie unterschiedliche Funktionssätze haben, erstellen Sie ein Portabilitätsproblem. Wenn es sich um Ware handelt, wählen Sie entweder die "Standardeinstellung" (GCC, Clang oder VS). Wenn Sie sich für die letzten 5% interessieren, haben Sie einen Benchmark-Off.
Wenn Sie in Ihrer Freizeit oder zu Forschungszwecken in Programmiersprachen arbeiten, ist die Sprache wahrscheinlich moderner. Daher die Verbreitung von Toy Compilern für Scheme und ML. Obwohl OCaml für nicht-akademische Zwecke eine gewisse Zugkraft zu bekommen scheint.
Beachten Sie, dass dies je nach Sprache sehr unterschiedlich ist. Java hat im Wesentlichen die Sun / Oracle-Toolchain und die GNU-Toolchain. Python hat verschiedene Compiler, von denen keiner im Vergleich zum Standardinterpreter wirklich respektiert wird. Rust und Go haben jeweils genau eine Implementierung. C # hat Microsoft und Mono.
quelle
1000 * 0
ist immer noch0
.int
, und erfordert, dass verschiedene Compiler denselben Quellcode auf sehr unterschiedliche Weise interpretieren.6g
/8g
/… Toolchain und gccgo). Es gab auch eine sehr interessante proprietäre kommerzielle Implementierung namens erGo, die a) eine native Windows-Implementierung von Go zu einer Zeit war, als weder gccgo noch der ursprüngliche Go-Compiler unter Windows sehr gut funktionierten, b) eine Firma, die lange auf Go setzte bevor es überhaupt 1.0 wurde, und c) die erste Implementierung von Go in Go (gccgo und 6g / 8g sind beide in C geschrieben). Sowohl das Projekt als auch das Unternehmen verschwanden jedoch, bevor sie die Closed Beta verlassen hatten.C / C ++ ist einzigartig in kompilierten Sprachen, da es drei Hauptimplementierungen einer gemeinsamen Spezifikation enthält.
Nach der Regel, alles zu verwerfen, was nicht oft verwendet wird, hat jede andere kompilierte Sprache 0 zu 1.
Und ich denke, Javascript ist der einzige Grund, warum Sie "kompiliert" angeben müssen.
quelle
uint16_t a=48000u; unsigned uint32_t b=(a*a)/2;
als Zuweisung zumb
Wert 8192. Einige definieren ihn als Zuweisung zu 1152000000. Die meisten betrachten ihn heutzutage als undefiniertes Verhalten und speichern wahrscheinlich 3299483648, versprechen dies jedoch nicht.2
oder2u
anscheinend./2u
? Überlauf ohne Vorzeichen ist definiert (als Modulo 2 ^ N für implementierungsdefiniertes N), aber Division kann nicht einmal überlaufen.int
, deren Produkt jedoch nicht zu diesem Typ passen würde. Das Erzwingen dieses Ergebnisses auf int ohne Vorzeichen würde wahrscheinlich die Interpretation des resultierenden Werts ändern, das undefinierte Verhalten aus der vorhergehenden Berechnung jedoch nicht negieren.Also, was ist Ihre Zielsprache?
SML-Compiler zielen häufig auf C oder so etwas wie LLVM (oder wie in Ihrem Link, der JVM oder JavaScript).
Wenn Sie C kompilieren, liegt das nicht daran, dass Sie zur JVM gehen. Du wirst etwas Schlimmeres als C. Weit schlimmer. Und dann können Sie diese kleine Hölle ein paar Mal für alle Ihre Zielplattformen duplizieren.
Und sicher, C ist nicht C ++, aber ich würde sagen, dass es näher an C ++ liegt als Schema. Es hat eine eigene Untergruppe von undefiniertem Verhalten Bösartigkeit (ich sehe Sie Größe der eingebauten Typen). Und wenn Sie diese Kleinigkeiten vermasseln (oder "richtig", aber unerwartet "machen"), verfügen Sie über jahrzehntelangen Code auf wichtigen Systemen, der Ihnen sagt, wie schrecklich Sie sind. Wenn Sie einen SML-Compiler vermasseln, funktioniert er einfach nicht - und jemand könnte es bemerken. Irgendwann mal.
quelle
int
32 oder 64 Bit, aber es kann so klein wie 16 Bit sein. Es ist überhaupt nicht schwer, eine Zahl außerhalb des Bereichs von zu produzieren,[−32767, +32767]
und derint
Überlauf ist UB. Es gibt auchchar
/short
zu gefördert zu werdenint
oderunsigned int
je nachdem , obint
jeder Wert des ursprünglichen Typs darstellen kann, die weiter eine Umwandlung von auslösen könnenint
zu ,unsigned int
wenn die Operanden hatten verschiedene Typen und wurde anders umgesetzt, und möglicherweise eine andere Umwandlung , wenn Sie das Ergebnis einer Variablen zuweisen .