Ich habe mich kürzlich gefragt, wann ich C über C ++ verwenden soll und umgekehrt? Zum Glück hat mich schon jemand geschlagen und obwohl es eine Weile gedauert hat, konnte ich alle Antworten und Kommentare zu dieser Frage verdauen.
Ein Punkt in diesem Beitrag wird jedoch immer wieder angesprochen, ohne Beispiel, Bestätigung oder Erklärung:
"C-Code ist gut, wenn Sie mehrere Sprachbindungen für Ihre Bibliothek haben möchten."
Das ist eine Umschreibung. Ich sollte beachten, dass mehrere Leute darauf hinweisen, dass mehrere Sprachbindungen in C ++ möglich sind (über einige extern
Funktionen), aber dennoch, wenn Sie diesen Beitrag in seiner Gesamtheit lesen, ist es ziemlich offensichtlich, dass C ideal für Portabilität / Sprachbindung ist. Meine Frage ist: warum?
Kann jemand bitte konkrete Gründe angeben, warum das Schreiben von Bibliotheken in C eine einfachere Bindung und / oder Portabilität in anderen Sprachen ermöglicht?
Antworten:
C verfügt über eine sehr viel einfachere Schnittstelle, und die Regeln für die Konvertierung einer Quellcode-Schnittstelle in eine Binärschnittstelle sind so einfach, dass die Generierung externer Schnittstellen, an die eine Bindung hergestellt werden soll, gut etabliert ist. C ++ hat andererseits eine unglaublich komplizierte Oberfläche, und die Regeln für die ABI-Bindung sind weder formal noch in der Praxis standardisiert. Das bedeutet, dass so gut wie jeder Compiler für jede Sprache für jede Plattform an eine externe C-Schnittstelle gebunden werden kann und genau weiß, was zu erwarten ist. Bei einer C ++ - Schnittstelle ist dies jedoch im Wesentlichen unmöglich, da sich die Regeln in Abhängigkeit davon ändern, welcher Compiler, welche Version und welche Plattform, mit der der C ++ - Code erstellt wurde.
quelle
extern "C"
dies ist jedoch noch ein weiterer Arbeitsschritt, der gegen die von C ++ bereitgestellten Funktionen abgewogen werden sollte)extern "C"
.Wenn Sie versuchen, mit einem Sprecher einer anderen Sprache zu kommunizieren, ist Pidgin einfacher als Shakespeare-Englisch.
Die Konzepte von C - Funktionsaufrufe, Zeiger und mit NULL abgeschlossene Zeichenfolgen - sind sehr einfach, sodass andere Sprachen sie problemlos gut genug implementieren können, um C-Funktionen aufzurufen. Aus historischen Gründen sind viele andere Sprachen in C implementiert, was den Aufruf von C-Funktionen noch einfacher macht.
C ++ fügt einiges hinzu - Klassen mit Vererbung und vtables und Zugriffsmodifikatoren; Ausnahmen mit Stapelabwicklung und Änderung des Kontrollflusses; Vorlagen. All dies erschwert es anderen Sprachen, C ++ - Bindungen zu verwenden: Im besten Fall muss mehr "Klebe" - oder Interoperabilitätscode implementiert werden, und im schlimmsten Fall werden die Konzepte nicht direkt übersetzt (aufgrund von Unterschieden in Klassenmodellen, Ausnahmebehandlung, usw.). Insbesondere für Vorlagen, die einfach verwendet (instanziiert) werden, ist normalerweise ein Kompilierungsschritt mit einem C ++ - Compiler erforderlich, was die Verwendung in anderen Umgebungen erheblich erschwert.
Trotzdem ist es möglich, die Schwierigkeit, Bindungen aus einer C ++ - Bibliothek für eine andere Sprache bereitzustellen, zu überschätzen:
extern "C"
, sodass Sie Sprachbindungen im C-Stil (mit der Einfachheit und Kompatibilität von C-Bindungen) aus einer C ++ - Bibliothek exportieren können (mit der Einschränkung, dass Sie keine C ++ - spezifischen Funktionen verfügbar machen können). .quelle
C ist eine der ältesten Sprachen, die es noch gibt. Das ABI ist einfach, und praktisch jedes Betriebssystem, das heute noch verwendet wird, wurde darauf geschrieben . Während einige dieser Betriebssysteme Dinge hinzugefügt haben, z. B. in C # /. NET oder was auch immer oben drauf ist, sind sie unten in C. sehr durchdrungen.
Das bedeutet, dass praktisch jede Programmiersprache eine Schnittstelle zu C-Bibliotheken benötigt , um die vom Betriebssystem bereitgestellten Funktionen nutzen zu können . Perl, Java, C ++, sie alle nativ Möglichkeiten bieten , um „C zu sprechen“, weil sie mussten , wenn sie jedes einzelne Rad neu erfinden , gibt es nicht wollte.
Dies macht C zum Latein der Programmiersprachen. (Wie viele Jahre Internet vor dieser Metapher muss "das Englisch der Programmiersprachen" sein?)
Wenn Sie Ihre Bibliothek in C schreiben, erhalten Sie (offensichtlich) kostenlos eine C-kompatible Schnittstelle. Wenn Sie Ihre Bibliothek in C ++ schreiben, können Sie C-Bindungen über die
extern "C"
von Ihnen erwähnten Deklarationen abrufen.Allerdings können Sie diese Bindungen erhalten nur für die Funktionalität , die in C ausgedrückt werden kann .
Ihre Bibliotheks-API kann also nicht ...
Ein einfaches Beispiel: Sie müssten dafür sorgen, dass Ihre exportierten Funktionen anstelle von (oder in diesem Fall) arrays ( ) annehmen und zurückgeben .
[]
std::vector
std::string
Damit können Sie nicht nur den Kunden Ihrer Bibliothek nicht die Vorteile von C ++ bieten, sondern müssen auch zusätzliche Anstrengungen unternehmen, um Ihre Bibliotheks-API von C ++ in "C-kompatibel" (
extern "C"
) zu "übersetzen" .Aus diesem Grund könnte darauf hingewiesen werden, dass C die bessere Wahl für die Implementierung einer Bibliothek ist. Ich persönlich denke, die Vorteile von C ++ überwiegen immer noch den für eine
extern "C"
API erforderlichen Aufwand , aber das bin nur ich.quelle
Lassen Sie die Details weg, die andere Antworten bereits liefern:
Der Grund, warum so viele Sprachen eine C-Bindung bereitstellen, ist, dass alle * nix- und Windows-Betriebssysteme den größten Teil ihrer Betriebssystem-API über eine C-Schnittstelle verfügbar machen. Daher muss die Sprachimplementierung bereits eine Schnittstelle zu C aufweisen, um auf den Haupt-Oses ausgeführt werden zu können. Daher ist es unkompliziert, auch die direkte Kommunikation mit einer beliebigen C-Schnittstelle aus der Sprache heraus anzubieten.
quelle
Es gibt keinen Grund. Wenn die Semantik, die Sie ausdrücken möchten, grundsätzlich C-kompatibel ist und nicht so etwas wie Vorlagen, gibt es keinen Grund, warum Sie sie einfacher binden können, wenn die Implementierung in C geschrieben ist. Tatsächlich ist es per Definition so ziemlich so, dass eine C-Schnittstelle sein kann Wird von jeder Implementierung ausgefüllt, die den Binärvertrag erfüllen kann, einschließlich einer Implementierung in einer anderen Sprache. Es gibt andere Sprachen als C ++, die C-Binärverträge implementieren können, die auf diese Weise funktionieren.
Worauf es wirklich ankommt, sind Leute, die keine neuen Sprachen oder Ideen lernen wollen, die tatsächlich nützliche Semantiken oder Funktionen haben, und verzweifelt versuchen, einen Grund zu finden, um in der Dinosaurier-Ära zu bleiben.
quelle
Bei der Verbindung mit einer anderen Sprache gibt es zwei Hauptachsen:
C hat in diesen beiden Punkten einen Vorteil gegenüber C ++:
Nun, warum haben die meisten Sprachen einen ähnlichen Satz von Konzepten als C, kann daran liegen, dass es entweder "einfach" oder "bereits vorhanden" ist; es spielt jedoch keine Rolle, der Punkt ist, dass sie es tun.
Im Gegenteil, C ++ hat komplexe Konzepte, und das ABI wird von jedem Compiler festgelegt (obwohl viele das Itanimum ABI einhalten, außer unter Windows ...). Es gab tatsächlich einen Vorschlag von Herb Sutter, dass Betriebssysteme ein C ++ - ABI (pro Betriebssystem) reparieren, um dieses Problem teilweise zu beheben. Man sollte auch beachten, dass ein C ++ FFI möglich ist, D versucht es 3 .
1 Mit Ausnahme von variadics (
...
) sind diese nicht einfach2 Hat C einen Standard-ABI?
3 Schnittstelle von D zu Legacy-C ++ - Code
quelle
Grundsätzlich kommt es auf die ABI-Standardisierung an. Während weder C noch C ++ ein standardisiertes ABI haben, mit dem andere Sprachen die Schnittstelle zwischen geschriebenen Binärdateien herstellen können, ist C zu einem de-facto-Standard geworden, jeder kennt es und jeder andere kann dieselben einfachen Regeln verwenden, die die Sprache in Bezug auf hat Typen und Funktionsaufrufe.
C ++ könnte ein Standard-ABI haben, aber Stroustrup hat gesagt, dass er die Notwendigkeit eines solchen nicht sieht. Er sagt auch, dass es schwierig sein würde, einen Konsens der Compiler-Autoren zu erzielen (obwohl ich bezweifle, dass - das C ++ - Standardkomitee eine ABI herausgeben würde, die den bestehenden ähnelt, und Compiler-Autoren einfach die nächste Version ihrer Compiler ändern würden, die gelegentlich nicht mit Binaries kompatibel sind Ich erinnere mich, dass ich einige Bibliotheken mit einem neuen Sun-Compiler neu kompiliert habe und festgestellt habe, dass sie nicht mit den alten funktionieren.
Sie werden bemerken, dass einige Unternehmen bereits in den 90er Jahren ein Standard-ABI verwendet haben. Microsoft hat diesen Prozess mit COM begonnen und heute das WinRT-ABI verfeinert (nicht zu verwechseln mit dem anderen WinRT, auf das verwiesen wird) auf einen Tabellentyp (OS), mit dem in C # geschriebene Programme mit in C oder C ++ geschriebenen Bibliotheken kommunizieren können (dh die Microsoft-eigene OS-Schicht wird in C ++ geschrieben, mit WinRT verfügbar gemacht und von C # -Anwendungen verwendet, wenn sie eine beliebige OS-Laufzeitroutine aufrufen)
Es gibt nicht viel, was jemand tun kann, es sei denn, ein Normungsgremium greift auf diese Situation zu und behebt sie. Microsoft sieht den Wert offensichtlich darin und hat Schritte unternommen, um ihn für ihre Plattform zu beheben.
Die Antwort ist also, dass C keine Sprachbindungen bereitstellt. Es kommt vor, dass niemand zugehört hat und sie trotzdem konsumiert.
quelle
Alle Antworten bleiben hinter dem eigentlichen Problem zurück: Durch das Kompilieren von C ++ wird "Name Mangling" eingeführt, sodass Binärdateien nicht mit "einfachen" Funktionsaufrufen kompatibel sind.
Alles ABI-Zeug ist nur ein Versuch, es zu standardisieren.
Im Allgemeinen kann nicht garantiert werden, dass Sie Funktionen, die mit verschiedenen Compilern kompiliert wurden, vernetzen können, auch wenn Sie sich an C ++ halten. Früher war es sicher, dass sie nicht kompatibel sind, aber heute schleicht sich die Standardisierung ein;)
OTOH C wurde genau als "High Level Assembly" konzipiert und ermöglicht alle Arten von einfachen Schnittstellen. Es sollte nicht überraschen, dass es besser für sprachübergreifende Vorlieben geeignet ist.
Randnotiz: Der ursprüngliche C ++ - Compiler (cfront) produzierte tatsächlich eine C-Quelle, die kompiliert werden musste, genau wie gcc, das Assembly "under the hood" produziert.
quelle