Warum können C-Funktionen nicht namengebunden werden?

136

Ich hatte kürzlich ein Interview und eine Frage war, was die Verwendung extern "C"in C ++ - Code ist. Ich antwortete, dass es C-Funktionen in C ++ - Code verwenden soll, da C keine Namensverknüpfung verwendet. Ich wurde gefragt, warum C keine Namensverknüpfung verwendet, und um ehrlich zu sein, konnte ich nicht antworten.

Ich verstehe, dass der C ++ - Compiler beim Kompilieren von Funktionen der Funktion einen speziellen Namen gibt, hauptsächlich weil wir in C ++ überladene Funktionen mit demselben Namen haben können, die zum Zeitpunkt der Kompilierung aufgelöst werden müssen. In C bleibt der Name der Funktion gleich oder möglicherweise mit einem _ davor.

Meine Frage lautet: Was ist falsch daran, dem C ++ - Compiler zu erlauben, auch C-Funktionen zu entstellen? Ich hätte angenommen, dass es egal ist, welche Namen der Compiler ihnen gibt. Wir rufen Funktionen in C und C ++ auf die gleiche Weise auf.

Ingenieur999
quelle
75
C nicht brauchen die Namen mangle, weil es nicht Funktion Überlastung hat.
EOF
9
Wie verknüpfen Sie C-Bibliotheken mit C ++ - Code, wenn der C ++ - Compiler die Funktionsnamen entstellt?
Mat
6
"Ich antwortete, dass C-Funktionen in C ++ - Code verwendet werden sollen, da C keine Namensverknüpfung verwendet." - Ich denke, es ist umgekehrt. Externes "C" macht die C ++ - Funktionen in einem C-Compiler verwendbar. Quelle
Rozina
3
@ Engineer999: Und wenn Sie die Teilmenge von C, die auch C ++ ist, mit einem C ++ - Compiler kompilieren, werden die Funktionsnamen tatsächlich entstellt. Wenn Sie jedoch Binärdateien verknüpfen möchten, die mit verschiedenen Compilern erstellt wurden, möchten Sie keine Namensverknüpfung.
EOF
13
C macht Mangelnamen. In der Regel ist der verstümmelte Name der Name der Funktion, der ein Unterstrich vorangestellt ist. Manchmal ist es der Name der Funktion, gefolgt von einem Unterstrich. extern "C"sagt, den Namen genauso zu entstellen, wie es "der" C-Compiler tun würde.
Pete Becker

Antworten:

187

Es wurde oben irgendwie beantwortet, aber ich werde versuchen, die Dinge in einen Zusammenhang zu bringen.

Zuerst kam C zuerst. Als solches ist C eine Art "Standard". Namen werden nicht entstellt, weil dies einfach nicht der Fall ist. Ein Funktionsname ist ein Funktionsname. Ein Global ist ein Global und so weiter.

Dann kam C ++. C ++ wollte in der Lage sein, den gleichen Linker wie C zu verwenden und mit in C geschriebenem Code zu verknüpfen. C ++ konnte das C jedoch nicht so belassen (oder fehlen), wie es ist. Schauen Sie sich das folgende Beispiel an:

int function(int a);
int function();

In C ++ sind dies unterschiedliche Funktionen mit unterschiedlichen Körpern. Wenn keiner von ihnen entstellt ist, werden beide als "Funktion" (oder "_Funktion") bezeichnet, und der Linker beschwert sich über die Neudefinition eines Symbols. Die C ++ - Lösung bestand darin, die Argumenttypen in den Funktionsnamen zu zerlegen. Also wird einer aufgerufen _function_intund der andere wird aufgerufen _function_void(kein tatsächliches Mangling-Schema) und die Kollision wird vermieden.

Jetzt haben wir ein Problem. Wenn dies int function(int a)in einem C-Modul definiert wurde und wir lediglich dessen Header (dh Deklaration) in C ++ - Code verwenden, wird der Compiler eine Anweisung an den Linker zum Importieren generieren _function_int. Als die Funktion im C-Modul definiert wurde, wurde sie nicht so genannt. Es wurde gerufen _function. Dies führt zu einem Linkerfehler.

Um diesen Fehler zu vermeiden, teilen wir dem Compiler während der Deklaration der Funktion mit, dass es sich um eine Funktion handelt, die mit einem C-Compiler verknüpft oder von diesem kompiliert werden soll:

extern "C" int function(int a);

Der C ++ - Compiler kann jetzt _functioneher importieren als _function_intund alles ist gut.

Shachar Shemesh
quelle
1
@ShacharShamesh: Ich habe dies an anderer Stelle gefragt, aber was ist mit dem Verknüpfen in C ++ - kompilierten Bibliotheken? Wenn der Compiler meinen Code durchläuft und kompiliert, der eine der Funktionen in einer C ++ - kompilierten Bibliothek aufruft, woher weiß er, welchen Namen er der Funktion entstellen oder geben soll, wenn er nur ihre Deklaration oder seinen Funktionsaufruf sieht? Woher wissen Sie, dass dort, wo es definiert ist, der Name auf etwas anderes beschränkt ist? Es muss also eine Standardmethode zum Verwalten von Namen in C ++ geben?
Engineer999
2
Jeder Compiler macht es auf seine eigene Art und Weise. Wenn Sie alles mit demselben Compiler kompilieren, spielt das keine Rolle. Aber wenn Sie versuchen, beispielsweise eine Bibliothek zu verwenden, die mit dem Compiler von Borland kompiliert wurde, aus einem Programm, das Sie mit dem Compiler von Microsoft erstellen, dann ... viel Glück; du wirst es brauchen :)
Mark VY
6
@ Engineer999 Haben Sie sich jemals gefragt, warum es keine portablen C ++ - Bibliotheken gibt, aber sie geben entweder genau an, welche Version (und Flags) des Compilers (und der Standardbibliothek) Sie verwenden müssen, oder exportieren einfach eine C-API? Los geht's. C ++ ist so ziemlich die am wenigsten tragbare Sprache, die jemals erfunden wurde, während C genau das Gegenteil ist. Es gibt Bemühungen in dieser Hinsicht, aber für den
Voo
1
@Voo Nun, theoretisch sollten Sie in der Lage sein, tragbaren Code zu schreiben, indem Sie sich einfach an den Standard halten, z. B. -std=c++11und die Verwendung von Dingen außerhalb des Standards vermeiden. Dies entspricht dem Deklarieren einer Java-Version (obwohl neuere Java-Versionen abwärtskompatibel sind). Es ist nicht der Standardfehler, den Compiler-spezifische Erweiterungen und plattformabhängigen Code verwenden. Auf der anderen Seite können Sie ihnen keine Vorwürfe machen, da im Standard viele Dinge (insbesondere E / A, wie Steckdosen) fehlen. Das Komitee scheint das langsam aufzuholen. Korrigieren Sie mich, wenn ich etwas verpasst habe.
Mucaho
14
@mucaho: Sie sprechen über Quellportabilität / -kompatibilität. dh die API. Voo spricht von Binärkompatibilität ohne Neukompilierung. Dies erfordert ABI-Kompatibilität . C ++ - Compiler ändern regelmäßig ihren ABI zwischen den Versionen. (zB versucht g ++ nicht einmal, einen stabilen ABI zu haben. Ich gehe davon aus, dass sie den ABI nicht nur zum Spaß brechen, aber sie vermeiden keine Änderungen, die eine ABI-Änderung erfordern, wenn etwas zu gewinnen ist und kein anderer guter Weg es zu tun.).
Peter Cordes
45

Es ist nicht so, dass sie "nicht können", sie sind es im Allgemeinen nicht.

Wenn Sie eine Funktion in einer aufgerufenen C-Bibliothek aufrufen möchten foo(int x, const char *y), ist es nicht gut, wenn Ihr C ++ - Compiler dies in foo_I_cCP()ein Mangle-Schema zerlegt (oder was auch immer, hier wurde nur ein Mangling-Schema erstellt), nur weil dies möglich ist.

Dieser Name wird nicht aufgelöst, die Funktion befindet sich in C und ihr Name hängt nicht von der Liste der Argumenttypen ab. Der C ++ - Compiler muss dies also wissen und diese Funktion als C markieren, um das Mangeln zu vermeiden.

Denken Sie daran, dass sich die C-Funktion möglicherweise in einer Bibliothek befindet, deren Quellcode Sie nicht haben. Sie haben lediglich die vorkompilierte Binärdatei und den Header. Ihr C ++ - Compiler kann also nicht "es ist etwas Eigenes", er kann doch nicht ändern, was sich in der Bibliothek befindet.

entspannen
quelle
Dies ist der Teil, den ich vermisse. Warum sollte der C ++ - Compiler einen Funktionsnamen entstellen, wenn er seine Deklaration nur sieht oder sieht, dass er aufgerufen wird? Mangelt es nicht nur Funktionsnamen, wenn es ihre Implementierung sieht? Dies würde für mich sinnvoller sein
Engineer999
13
@ Engineer999: Wie können Sie einen Namen für die Definition und einen anderen für die Deklaration haben? "Es gibt eine Funktion namens Brian, die Sie aufrufen können." "Okay, ich rufe Brian an." "Entschuldigung, es gibt keine Funktion namens Brian." Es stellt sich heraus, dass es Graham heißt.
Leichtigkeitsrennen im Orbit
Was ist mit dem Verknüpfen in C ++ - kompilierten Bibliotheken? Wenn der Compiler unseren Code durchläuft und kompiliert, der eine der Funktionen in einer C ++ - kompilierten Bibliothek aufruft, woher weiß er, welchen Namen er der Funktion entstellen oder geben soll, wenn sie nur ihre Deklaration oder ihren Funktionsaufruf sieht?
Engineer999
1
@ Engineer999 Beide müssen sich auf das gleiche Mangeln einigen. Sie sehen also die Header-Datei (denken Sie daran, dass native DLLs nur sehr wenige Metadaten enthalten - Header sind diese Metadaten) und sagen: "Ah, richtig, Brian sollte wirklich Graham sein." Wenn dies nicht funktioniert (z. B. mit zwei inkompatiblen Mangling-Schemata), erhalten Sie keinen korrekten Link und Ihre Anwendung schlägt fehl. C ++ hat viele solche Inkompatibilitäten. In der Praxis müssen Sie dann den verstümmelten Namen explizit verwenden und das Verstümmeln auf Ihrer Seite deaktivieren (z. B. Sie weisen Ihren Code an, Graham auszuführen, nicht Brian). In tatsächlichen Praxis ... extern "C":)
Luaan
1
@ Engineer999 Ich könnte mich irren, aber haben Sie vielleicht Erfahrung mit Sprachen wie Visual Basic, C # oder Java (oder bis zu einem gewissen Grad sogar Pascal / Delphi)? Diese lassen Interop extrem einfach erscheinen. In C und insbesondere in C ++ ist es alles andere als. Es gibt viele Aufrufkonventionen, die Sie einhalten müssen, Sie müssen wissen, wer für welchen Speicher verantwortlich ist, und Sie müssen über die Header-Dateien verfügen, die Ihnen die Funktionsdeklarationen mitteilen, da die DLLs selbst nicht genügend Informationen enthalten - insbesondere im Fall von pure C. Wenn Sie keine Header-Datei haben, müssen Sie die DLL im Allgemeinen dekompilieren, um sie verwenden zu können.
Luaan
32

Was ist falsch daran, dem C ++ - Compiler zu erlauben, auch C-Funktionen zu entstellen?

Sie wären keine C-Funktionen mehr.

Eine Funktion ist nicht nur eine Signatur und eine Definition. Wie eine Funktion funktioniert, wird weitgehend von Faktoren wie der Aufrufkonvention bestimmt. Die für die Verwendung auf Ihrer Plattform angegebene "Application Binary Interface" beschreibt, wie Systeme miteinander kommunizieren. Das von Ihrem System verwendete C ++ - ABI gibt ein Namensverwaltungsschema an, damit Programme auf diesem System wissen, wie Funktionen in Bibliotheken usw. aufgerufen werden. (Lesen Sie das C ++ Itanium ABI für ein gutes Beispiel. Sie werden sehr schnell erkennen, warum es notwendig ist.)

Gleiches gilt für das C ABI auf Ihrem System. Einige C-ABIs verfügen tatsächlich über ein Namensverwaltungsschema (z. B. Visual Studio). Daher geht es hier weniger darum, die Namensverwaltung zu deaktivieren, als vielmehr darum, für bestimmte Funktionen von C ++ ABI zu C ABI zu wechseln. Wir markieren C-Funktionen als C-Funktionen, für die der C ABI (und nicht der C ++ ABI) relevant ist. Die Deklaration muss mit der Definition übereinstimmen (sei es im selben Projekt oder in einer Bibliothek eines Drittanbieters), andernfalls ist die Deklaration sinnlos. Ohne das weiß Ihr System einfach nicht, wie diese Funktionen zu finden / aufzurufen sind.

Warum Plattformen C- und C ++ - ABIs nicht als gleich definieren und dieses "Problem" beseitigen, ist teilweise historisch - die ursprünglichen C-ABIs reichten für C ++ nicht aus, da Namespaces, Klassen und Operatorüberladungen vorhanden sind von denen irgendwie auf computerfreundliche Weise im Namen eines Symbols dargestellt werden müssen - aber man könnte auch argumentieren, dass es für die C-Community unfair ist, C-Programme jetzt an C ++ zu halten, was sich mit einer massiv komplizierteren Situation abfinden müsste ABI nur für einige andere Leute, die Interoperabilität wollen.

Leichtigkeitsrennen im Orbit
quelle
2
+int(PI/3), aber mit einem Körnchen Salz: Ich würde sehr vorsichtig von "C ++ ABI" sprechen ... AFAIK, es gibt Versuche , C ++ ABIs zu definieren, aber keine wirklichen De-facto / De-Jure- Standards - wie isocpp.org/files /papers/n4028.pdf besagt (und ich stimme voll und ganz zu), zitieren, es ist zutiefst ironisch, dass C ++ tatsächlich immer eine Möglichkeit unterstützt hat, eine API mit einem stabilen binären ABI zu veröffentlichen - indem über externes „C“ auf die C-Teilmenge von C ++ zurückgegriffen wird ”. . C++ Itanium ABIist genau das - etwas C ++ ABI für Itanium ... wie auf stackoverflow.com/questions/7492180/c-abi-issues-list
3
@vaxquis: Ja, nicht "C ++ 's ABI", sondern "ein C ++ ABI" auf die gleiche Weise, wie ich einen "Hausschlüssel" habe, der nicht bei jedem Haus funktioniert. Ich schätze, es könnte klarer sein, obwohl ich versucht habe, es so klar wie möglich zu machen, indem ich mit dem Satz "Das von Ihrem System verwendete C ++ - ABI " begonnen habe . Ich habe den Klärer der Kürze halber in späteren Äußerungen fallen lassen, aber ich werde eine Änderung akzeptieren, die die Verwirrung hier verringert!
Leichtigkeitsrennen im Orbit
1
AIUI C abi war in der Regel eine Eigenschaft einer Plattform, während C ++ - ABIs in der Regel eine Eigenschaft eines einzelnen Compilers und häufig sogar eine Eigenschaft einer einzelnen Version eines Compilers waren. Wenn Sie also eine Verbindung zwischen Modulen herstellen möchten, die mit Tools verschiedener Hersteller erstellt wurden, müssen Sie ein C abi für die Schnittstelle verwenden.
Plugwash
Die Aussage "Namensverfälschte Funktionen wären keine C-Funktionen mehr" ist übertrieben - es ist durchaus möglich, namensverfälschte Funktionen aus einfachem Vanille-C aufzurufen, wenn der entstellte Name bekannt ist. Dass sich der Name ändert, macht ihn nicht weniger an das C ABI gebunden, dh macht es nicht weniger an eine C-Funktion. Umgekehrt
Peter - Reinstate Monica
@ PeterA.Schneider: Ja, die Überschrift ist übertrieben. Das gesamte Rest der Antwort enthält die relevanten sachlichen Details.
Leichtigkeitsrennen im Orbit
21

MSVC in der Tat tut mangle C Namen, wenn auch in einer einfachen Art und Weise. Es hängt manchmal an @4oder eine andere kleine Zahl. Dies bezieht sich auf Aufrufkonventionen und die Notwendigkeit einer Stapelbereinigung.

Die Prämisse ist also nur fehlerhaft.

MSalters
quelle
2
Das ist nicht wirklich Name Mangling. Es handelt sich lediglich um eine herstellerspezifische Namens- (oder Namensverzierungs-) Konvention, um zu verhindern, dass Probleme mit ausführbaren Dateien mit DLLs verknüpft werden, die mit Funktionen mit unterschiedlichen Aufrufkonventionen erstellt wurden.
Peter
2
Was ist mit einem vorangestellten _?
OrangeDog
12
@ Peter: Im wahrsten Sinne des Wortes das Gleiche.
Leichtigkeitsrennen im Orbit
5
@Frankie_C: "Aufrufer bereinigt den Stapel" wird von keinem C-Standard angegeben: Keine der Aufrufkonventionen ist aus sprachlicher Sicht mehr Standard als die andere.
Ben Voigt
2
Und aus MSVC-Sicht ist die "Standard-Anrufkonvention" genau das, woraus Sie auswählen /Gd, /Gr, /Gv, /Gz. (Das heißt, die Standardaufrufkonvention wird verwendet, es sei denn, eine Funktionsdeklaration gibt explizit eine Aufrufkonvention an.) Sie denken darüber nach, __cdeclwelche Standardkonvention für Anrufe gilt.
MSalters
13

Es ist sehr üblich, Programme zu haben, die teilweise in C und teilweise in einer anderen Sprache geschrieben sind (oft Assemblersprache, manchmal aber auch Pascal, FORTRAN oder etwas anderes). Es ist auch üblich, dass Programme verschiedene Komponenten enthalten, die von verschiedenen Personen geschrieben wurden, die möglicherweise nicht für alles den Quellcode haben.

Auf den meisten Plattformen gibt es eine Spezifikation, die häufig als ABI (Application Binary Interface) bezeichnet wird und beschreibt, was ein Compiler tun muss, um eine Funktion mit einem bestimmten Namen zu erstellen, die Argumente bestimmter Typen akzeptiert und einen Wert eines bestimmten Typs zurückgibt. In einigen Fällen kann ein ABI mehr als eine "Aufrufkonvention" definieren. Compiler für solche Systeme bieten häufig eine Möglichkeit, anzugeben, welche Aufrufkonvention für eine bestimmte Funktion verwendet werden soll. Auf dem Macintosh verwenden die meisten Toolbox-Routinen beispielsweise die Pascal-Aufrufkonvention. Der Prototyp für "LineTo" lautet also wie folgt:

/* Note that there are no underscores before the "pascal" keyword because
   the Toolbox was written in the early 1980s, before the Standard and its
   underscore convention were published */
pascal void LineTo(short x, short y);

Wenn der gesamte Code in einem Projekt mit demselben Compiler kompiliert wurde, spielt es keine Rolle, welchen Namen der Compiler für jede Funktion exportiert hat. In vielen Situationen muss C-Code jedoch Funktionen aufrufen, die mit anderen Tools und kompiliert wurden kann mit dem vorliegenden Compiler nicht neu kompiliert werden [und befindet sich möglicherweise nicht einmal in C]. Die Möglichkeit, den Linkernamen zu definieren, ist daher für die Verwendung solcher Funktionen von entscheidender Bedeutung.

Superkatze
quelle
Ja, das ist die Antwort. Wenn es nur C und C ++ ist, ist es schwer zu verstehen, warum es so gemacht wird. Um zu verstehen, müssen wir die Dinge in den Kontext der alten Art der statischen Verknüpfung stellen. Statische Verknüpfungen scheinen für Windows-Programmierer primitiv zu sein, aber dies ist der Hauptgrund, warum C Namen nicht entstellen kann.
user34660
2
@ user34660: Nicht qutie. Dies ist der Grund, warum C nicht die Existenz von Features vorschreiben kann, deren Implementierung entweder das Zerlegen exportierbarer Namen erfordern würde oder die Existenz mehrerer gleichnamiger Symbole zulassen würde, die sich durch sekundäre Merkmale auszeichnen.
Supercat
Wissen wir, dass es Versuche gab, solche Dinge zu "beauftragen", oder dass solche Dinge Erweiterungen waren, die für C vor C ++ verfügbar waren?
user34660
@ user34660: Betreff "Statische Verknüpfungen scheinen für Windows-Programmierer primitiv zu sein ...", aber dynamische Verknüpfungen scheinen für Linux-Benutzer manchmal eine große PITA zu sein, wenn bei der Installation von Programm X (wahrscheinlich in C ++ geschrieben) bestimmte Versionen aufgespürt und installiert werden müssen von Bibliotheken, von denen Sie bereits verschiedene Versionen auf Ihrem System haben.
Jamesqf
@jamesqf, ja, Unix hatte vor Windows keine dynamische Verknüpfung. Ich weiß sehr wenig über dynamische Verknüpfungen unter Unix / Linux, aber es scheint nicht so nahtlos zu sein, wie es in einem Betriebssystem im Allgemeinen sein könnte.
user34660
12

Ich werde eine weitere Antwort hinzufügen, um einige der tangentialen Diskussionen anzusprechen, die stattgefunden haben.

Das C ABI (Application Binary Interface) forderte ursprünglich die Übergabe von Argumenten auf dem Stapel in umgekehrter Reihenfolge (dh von rechts nach links verschoben), wobei der Aufrufer auch den Stapelspeicher freigibt. Das moderne ABI verwendet tatsächlich Register zum Übergeben von Argumenten, aber viele der Überlegungen zum Mangeln gehen auf das Übergeben des ursprünglichen Stapelarguments zurück.

Im Gegensatz dazu schob der ursprüngliche Pascal ABI die Argumente von links nach rechts, und der Angerufene musste die Argumente platzen lassen. Der ursprüngliche C ABI ist dem ursprünglichen Pascal ABI in zwei wichtigen Punkten überlegen. Die Argument-Push-Reihenfolge bedeutet, dass der Stapelversatz des ersten Arguments immer bekannt ist. Dies ermöglicht Funktionen mit einer unbekannten Anzahl von Argumenten, wobei die frühen Argumente steuern, wie viele andere Argumente es gibt (ala printf).

Die zweite Art und Weise, in der der C ABI überlegen ist, ist das Verhalten, falls sich Anrufer und Angerufene nicht darüber einig sind, wie viele Argumente es gibt. Im Fall C passiert nichts Schlimmes, solange Sie nicht auf Argumente zugreifen, die über das letzte hinausgehen. In Pascal wird die falsche Anzahl von Argumenten aus dem Stapel entfernt und der gesamte Stapel ist beschädigt.

Das ursprüngliche Windows 3.1 ABI basierte auf Pascal. Als solches wurde der Pascal ABI verwendet (Argumente in der Reihenfolge von links nach rechts, Callee Pops). Da eine Nichtübereinstimmung der Argumentnummer zu einer Stapelbeschädigung führen kann, wurde ein Mangling-Schema gebildet. Jeder Funktionsname wurde mit einer Zahl entstellt, die die Größe seiner Argumente in Bytes angibt. Also auf 16-Bit-Maschine die folgende Funktion (C-Syntax):

int function(int a)

Wurde verstümmelt function@2, weil intes zwei Bytes breit ist. Dies wurde durchgeführt, damit der Linker die Funktion nicht findet, wenn die Deklaration und Definition nicht übereinstimmen, anstatt den Stapel zur Laufzeit zu beschädigen. Wenn das Programm dagegen verknüpft ist, können Sie sicher sein, dass am Ende des Aufrufs die richtige Anzahl von Bytes aus dem Stapel entfernt wird.

32-Bit-Windows und höher verwenden stdcallstattdessen das ABI. Es ähnelt dem Pascal ABI, außer dass die Push-Reihenfolge wie in C von rechts nach links ist. Wie beim Pascal ABI werden beim Durchführen des Namens die Byte-Größe der Argumente in den Funktionsnamen zerlegt, um eine Stapelbeschädigung zu vermeiden.

Im Gegensatz zu Behauptungen, die an anderer Stelle hier gemacht wurden, werden die Funktionsnamen vom C ABI selbst in Visual Studio nicht entstellt. Umgekehrt sind Mangling-Funktionen, die mit der stdcallABI-Spezifikation dekoriert sind, nicht nur für VS verfügbar. GCC unterstützt dieses ABI auch beim Kompilieren für Linux. Dies wird häufig von Wine verwendet, das einen eigenen Loader verwendet, um die Laufzeitverknüpfung von Linux-kompilierten Binärdateien mit Windows-kompilierten DLLs zu ermöglichen.

Shachar Shemesh
quelle
9

C ++ - Compiler verwenden die Namensverwaltung, um eindeutige Symbolnamen für überladene Funktionen zuzulassen, deren Signatur ansonsten identisch wäre. Grundsätzlich werden auch die Arten von Argumenten codiert, was Polymorphismus auf funktionsbasierter Ebene ermöglicht.

C benötigt dies nicht, da es keine Überladung von Funktionen zulässt.

Beachten Sie, dass das Mangeln von Namen ein (aber sicherlich nicht der einzige!) Grund ist, warum man sich nicht auf ein 'C ++ ABI' verlassen kann.

dgrine
quelle
8

C ++ möchte in der Lage sein, mit C-Code zu interagieren, der mit ihm verknüpft ist oder mit dem er verknüpft ist.

C erwartet nicht namengebundene Funktionsnamen.

Wenn C ++ es entstellt, findet es die exportierten nicht entstellten Funktionen von C nicht, oder C findet die exportierten Funktionen von C ++ nicht. Der C-Linker muss den Namen erhalten, den er selbst erwartet, da er nicht weiß, dass er von C ++ kommt oder zu C ++ geht.

Yakk - Adam Nevraumont
quelle
3

Wenn Sie die Namen von C-Funktionen und -Variablen entstellen, können deren Typen zum Zeitpunkt der Verknüpfung überprüft werden. Derzeit können Sie in allen (?) C-Implementierungen eine Variable in einer Datei definieren und in einer anderen als Funktion aufrufen. Oder Sie können eine Funktion mit einer falschen Signatur deklarieren (z. B. void fopen(double)und dann aufrufen).

Ich schlug 1991 ein Schema für die typsichere Verknüpfung von C-Variablen und -Funktionen durch Mangeln vor. Das Schema wurde nie übernommen, da dies, wie andere hier angemerkt haben, die Abwärtskompatibilität zerstören würde.

Diomidis Spinellis
quelle
1
Sie meinen "erlauben, dass ihre Typen zur Verbindungszeit überprüft werden". Typen werden zur Kompilierungszeit überprüft, aber die Verknüpfung mit nicht verschränkten Namen kann nicht überprüfen, ob die in den verschiedenen Kompilierungseinheiten verwendeten Deklarationen übereinstimmen. Und wenn sie nicht übereinstimmen, ist es Ihr Build-System, das grundlegend kaputt ist und repariert werden muss.
cmaster - wieder herstellen Monica