43 Stimmen

Welche Probleme kann ich beim Kompilieren von C-Code mit einem C++-Compiler erwarten?

Wenn Sie eine vorhandene C-Code-Basis übernehmen und mit einem C++-Compiler kompilieren, mit welchen Problemen können Sie rechnen? Zum Beispiel glaube ich, dass das Zuweisen eines Ganzzahlenwerts mit einem aufgezählten Typ in C++ fehlschlagen wird, während es in C legal ist (wenn auch etwas unangenehm).

Wenn ich nicht alle meine C-Dateien in extern C { ... } einhülle, werde ich dann Namensverwirrung bekommen, wo ich es am wenigsten erwarte? Gibt es einen Grund, warum ich das wirklich nicht tun sollte?

Zur Information: Wir haben eine sehr große Code-Basis in C geschrieben. Seit einigen Jahren springen wir durch Reifen, um Dinge zu tun, die über C++ (zum Beispiel selbstgebundene Vererbung) auf natürliche Weise möglich wären. Wir möchten langsam auf C++ umsteigen; indem wir unser CORBA-ähnliches Framework unterstützen und Module umgestalten, um den natürlicheren Ansatz von C++ nutzen zu können, während wir vorankommen.

39voto

Ville Laurikari Punkte 27255

Ich habe so etwas schon einmal gemacht. Die Hauptursache für Probleme war, dass C++ strenger in Bezug auf Typen ist, wie Sie vermutet haben. Sie müssen Umwandlungen hinzufügen, wo void* mit Zeigern anderer Typen gemischt sind. Zum Beispiel das Speichern von Speicherplatz:

Foo *foo;
foo = malloc(sizeof(*foo));

Der obige Code ist typischer C-Code, aber in C++ benötigt er eine Umwandlung:

Foo *foo;
foo = (Foo*)malloc(sizeof(*foo));

In C++ gibt es neue reservierte Wörter wie "class", "and", "bool", "catch", "delete", "explicit", "mutable", "namespace", "new", "operator", "or", "private", "protected", "friend" usw. Diese können nicht als Variablennamen verwendet werden.

Die oben genannten Probleme sind wahrscheinlich die häufigsten Probleme, wenn Sie alten C-Code mit einem C++-Compiler kompilieren. Eine vollständige Liste der Inkompatibilitäten finden Sie unter Inkompatibilitäten zwischen ISO-C und ISO-C++.

Sie fragen auch nach Namensverwürfelung. Ohne "extern 'C'"-Wrapper wird der C++-Compiler die Symbole verwürfeln. Das ist kein Problem, solange Sie nur einen C++-Compiler verwenden und nicht darauf vertrauen, dass Sie Symbole aus Bibliotheken mit dlsym() oder ähnlichem extrahieren.

26voto

Adam Rosenfield Punkte 373807

Siehe Inkompatibilitäten zwischen ISO C und ISO C++ für eine sehr detaillierte Liste aller Inkompatibilitäten. Es gibt viele subtile Probleme, einschließlich einiger, die sich nicht sofort in einem Compilerfehler manifestieren. Zum Beispiel könnte ein Problem die Größe von Zeichenkonstanten sein:

// In C wird 4 ausgegeben. In C++ wird 1 ausgegeben
printf("%d\n", sizeof('A'));

10voto

Steve Jessop Punkte 264569

Wenn ich nicht alle meine C-Dateien in "extern C { ... }" einhülle, werde ich Namensverwechselungen bekommen, wo ich es am wenigsten erwarte?

Es beißt dich, wenn du versuchst, C und C++ zusammenzufügen.

Ich habe viele Header-Dateien geschrieben, die Folgendes enthalten:

#ifdef __cplusplus
    extern "C" {
#endif

// rest of file

#ifdef __cplusplus
    }
#endif

Nach einer Weile verschmilzt es mit dem bestehenden Mehrfach-Include-Boilerplate und du siehst es nicht mehr. Aber du musst darauf achten, wo du es platzierst - normalerweise gehört es nach jedem include, das dein Header verwendet.

Gibt es einen Grund, warum ich das wirklich nicht tun sollte?

Wenn du sicher bist, dass du C und C++ nicht kombinieren wirst, dann gibt es meines Wissens keinen Grund, es zu tun. Aber bei der allmählichen Migration, die du beschreibst, ist es für alles mit einer veröffentlichten Schnittstelle unerlässlich, dass sowohl C-Komponenten als auch C++-Komponenten es verwenden müssen.

Der große Grund nicht zu tun, ist, dass es dich daran hindert, Funktionen zu überladen (zumindest in diesen Headern). Du könntest feststellen, dass du das tun möchtest, sobald du deinen gesamten Code auf C++ migriert und mit dem Warten/Refakturieren/Erweitern begonnen hast.

5voto

Graham Asher Punkte 1476

Im Allgemeinen werden Sie überhaupt keine Probleme haben. Ja, es gibt einige Inkompatibilitäten zwischen C und C++, aber sie scheinen nicht sehr oft aufzutreten, abgesehen von dem oben erwähnten malloc-Casting, das ziemlich trivial zu beheben ist.

Ich habe erfolgreich die folgenden Open-Source-C-Bibliotheken als C++ kompiliert und verwendet:

  • den Expat XML-Parser
  • den FreeType2-Schriftartenrasterizer
  • libjpeg: für JPEG-Bilder
  • libpng: für PNG-Bilder
  • die Zlib-Komprimierungsbibliothek

Der schwierigste Teil war das Hinzufügen von Namensraum-Umschließungen, was einige Stunden in Anspruch nahm, hauptsächlich aufgrund von #include-Anweisungen, die tief im Code vergraben waren und außerhalb des C++-Namensraums sein mussten.

Warum habe ich das gemacht? Weil ich eine kommerzielle Bibliothek verkaufe, die von Leuten direkt in ihre Apps eingebunden wurde; und manchmal wurden ihre Apps mit anderen Versionen von Expat, FreeType usw. verknüpft. Das führte zu Fehlern durch mehrfach definierte Symbole. Das sauberste war, alles in meiner Bibliothek zu verschieben und es in meinem Namensraum zu verstecken.

Allerdings habe ich das nicht mit allen Open-Source-Bibliotheken gemacht, die ich verwende. Einige haben noch keine Konflikte verursacht, und ich bin noch nicht dazu gekommen, sie zu beheben, was obwohl problemlos recht mühsam ist. Die interessante Ausnahme ist SQLite, das ich nicht zum Kompilieren in C++ bringen konnte. Also habe ich eine umfangreiche Suche und Ersetzung durchgeführt, indem ich jedem einzelnen nach außen sichtbaren Symbol einen Präfix (den Namen meines Produkts) hinzugefügt habe. Das hat das Problem meines Kunden gelöst.

3voto

piotr Punkte 5549

Ein weiteres Beispiel: In C++ gibt es keine implizite Umwandlung von ints in Enums, während es in C eine gibt. Du wirst einen Cast benötigen, wenn du es wirklich in C++ machen möchtest.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X