C++-Klassen- oder Struct-Kompatibilität mit C-Struct

Lesezeit: 9 Minuten

Benutzer-Avatar
Cem Kalyoncu

Ist es möglich, eine C++-Klasse oder -Struktur zu schreiben, die vollständig mit C-Struktur kompatibel ist? Mit Kompatibilität meine ich Größe des Objekts und Speicherorte der Variablen. Ich weiß, dass es böse ist, es zu benutzen *(point*)&pnt oder auch (float*)&pnt (in einem anderen Fall, in dem Variablen Gleitkommazahlen sind), aber bedenken Sie, dass dies aus Gründen der Leistung wirklich erforderlich ist. Es ist nicht logisch, den regulären Casting-Operator millionenfach pro Sekunde zu verwenden.

Nehmen Sie dieses Beispiel

Class Point {
    long x,y;
    Point(long x, long y) {
        this->x=x;
        this->y=y;
    }

    float Distance(Point &point) {
        return ....;
    }
};

Die C-Version ist eine POD-Struktur

struct point {
    long x,y;
};

  • Zu welchem ​​Zweck möchten Sie diese Kompatibilität? Möchten Sie Binärdaten von einem C++-Programm an ein AC-Programm übergeben, oder möchten Sie ein C++-Objekt an eine AC-Funktion übergeben?

    – Dima

    15. September 2009 um 20:39 Uhr

  • “Aber bedenken Sie, dass dies aus Gründen der Leistung wirklich erforderlich ist. Es ist nicht logisch, einen regulären Typ-Casting-Operator millionenfach pro Sekunde zu verwenden.” Das ergibt für mich keinen Sinn.

    – GManNickG

    15. September 2009 um 20:45 Uhr

  • @Dima: zu C-Funktion @GMan: nicht-böse Methode sollte Type-Casting-Operator definieren operator point() { point p; px=dies->x; py=this.y; gib p zurück; } Allerdings werde ich diese Punkte in zwei Fällen verwenden, die int eingegeben werden, um die Windows-Funktion zu übergeben, um die Cursorposition zu finden. Float-Typ wird als Vertices an OpenGL gesendet (während es in Float-Array konvertiert wird), zuerst wird einer pro Frame (350 Mal/Sek.) ausgeführt, der andere ist für 4 x gezeichnete Objekte x 350. Sie werden innerhalb eines Spiels verwendet Motor.

    – Cem Kalyoncu

    15. September 2009 um 22:33 Uhr

Benutzer-Avatar
Stephen C. Stahl

Am saubersten war es, von der C-Struktur zu erben:

struct point
{
    long x, y;
};

class Point : public struct point
{
  public:
    Point(long x, long y)
        {    this->x=x; this->y=y; }

    float Distance(Point &point)
        {                return ....;        }
}

Der C++-Compiler garantiert, dass der Strukturpunkt im C-Stil dasselbe Layout wie beim C-Compiler hat. Die C++-Klasse Point erbt dieses Layout für ihren Basisklassenteil (und da sie keine Daten oder virtuellen Elemente hinzufügt, hat sie dasselbe Layout). Ein Zeiger auf die Klasse Point wird ohne Umwandlung in einen Zeiger auf den Strukturpunkt konvertiert, da die Konvertierung in einen Basisklassenzeiger immer unterstützt wird. Sie können also Point-Objekte der Klasse verwenden und Zeiger auf sie frei an C-Funktionen übergeben, die einen Zeiger auf den Strukturpunkt erwarten.

Wenn es bereits eine C-Header-Datei gibt, die den Strukturpunkt definiert, können Sie diese natürlich einfach einschließen, anstatt die Definition zu wiederholen.

  • Dies ist, was ich gefunden habe. Vielen Dank!

    – Äonil

    17. März 2011 um 5:19 Uhr

  • Dies kann zu einem schrecklichen Durcheinander führen, da die Strukturmitglieder öffentlich sind. Es bricht im Grunde jede Kapselung vollständig.

    – Falscher Name

    15. Juni 2015 um 23:40 Uhr

  • @FakeName Das ist inhärent, wenn C beteiligt ist, siehe stackoverflow.com/questions/2522424/… Und Sie können mindestens den C++-Punkt kapseln, wenn Sie Ihre Vererbung durchführen protected anstelle von public. Siehe auch isocpp.org/wiki/faq/mixing-c-and-cpp#cpp-objs-passed-to-c

    – Antonio

    6. Oktober 2016 um 12:45 Uhr


Benutzer-Avatar
Jason Williams

Ja.

  • Verwenden Sie in beiden Sprachen dieselben Typen in derselben Reihenfolge
  • Stellen Sie sicher, dass die Klasse nichts Virtuelles enthält (damit kein vtable-Zeiger auf der Vorderseite hängen bleibt).
  • Abhängig von den verwendeten Compilern müssen Sie möglicherweise das Strukturpacken (normalerweise mit Pragmas) anpassen, um die Kompatibilität zu gewährleisten.

(bearbeiten)

  • Außerdem müssen Sie darauf achten, die sizeof() der Typen mit Ihren Compilern zu überprüfen. Zum Beispiel bin ich auf einen Compiler gestoßen, der Kurzschlüsse als 32-Bit-Werte gespeichert hat (wobei die meisten 16 verwenden). Ein häufigerer Fall ist, dass ein int normalerweise 32 Bit auf einer 32-Bit-Architektur und 64 Bit auf einer 64-Bit-Architektur ist.

  • Nach meiner Erfahrung sind Pack-Pragmas eine schlechte Idee. Wenn Sie die Elementvariablen so anordnen, dass sie eine natürliche Ausrichtung haben, sind Pack-Pragmas nicht erforderlich. Und wenn Du nicht Wenn Sie ihnen eine natürliche Ausrichtung zuweisen und versuchen, Pragmas zu verwenden, um dies zu beheben, können Sie auf zwei Probleme stoßen: 1) Die Pragmas funktionieren immer noch nicht. 2) Sie zwingen den Compiler, etwas falsch auszurichten, was der Prozessor nicht falsch ausrichten möchte Gleitkommazahlen. Zumindest auf PowerPC erzeugt ein falsch ausgerichteter Float einen Interrupt, der von der Software behandelt wird, das kann bedeutend Wirkungsleistung.

    – KeyserSoze

    15. September 2009 um 22:34 Uhr

  • Das Definieren eines C++-Objekts mit demselben Layout wie die C-Struktur funktioniert, aber es drückt die Absicht nicht so klar aus wie das Klasseninteresse aus der Struktur (siehe meine Antwort unten).

    – Stephen C. Stahl

    15. September 2009 um 23:18 Uhr

  • @keysersoze: Ja, natürliche Ausrichtung ist besser. Einige Compiler werden Daten jedoch immer noch anders packen, weshalb es sinnvoll ist, das Packen zu erwähnen. In der Tat habe ich vergessen zu erwähnen, dass ich auch auf die Mitgliedergrößen achten sollte. Ich werde meinen Beitrag bearbeiten, um diesen Punkt hinzuzufügen.

    – Jason Williams

    16. September 2009 um 7:10 Uhr

  • Das gesuchte Wort ist POD-Typen. Sie sind im Standard klar definiert, und im Grunde besteht ihr gesamter Zweck darin, mit C kompatibel zu sein.

    – jalf

    16. September 2009 um 10:00 Uhr

  • @jalf: Ja. Ich sah keinen Sinn darin, keyersozes guten Post über POD zu wiederholen. Ich meinte einfach, dass Sie (im allgemeinen Sinne) nur überprüfen müssen, ob die spezifischen Compiler, die Sie verwenden, identische Binärstrukturen erzeugen. Ich würde meinen Code testen, um dies zu überprüfen, unabhängig davon, welche Typen ich verwendet habe.

    – Jason Williams

    16. September 2009 um 11:39 Uhr

POD gilt für C++. Sie können Mitgliedsfunktionen haben. „Ein POD-Typ in C++ ist eine Aggregatklasse, die nur POD-Typen als Mitglieder enthält, keinen benutzerdefinierten Destruktor, keinen benutzerdefinierten Kopierzuweisungsoperator und keine nicht statischen Mitglieder des Zeiger-auf-Member-Typs hat.“

Sie sollten Ihre POD-Datenstrukturen so entwerfen, dass sie eine natürliche Ausrichtung haben und dann zwischen Programmen weitergegeben werden können, die von verschiedenen Compilern auf verschiedenen Architekturen erstellt wurden. Bei der natürlichen Ausrichtung ist der Speicheroffset eines beliebigen Members durch die Größe dieses Members teilbar. IE: Ein Float befindet sich an einer Adresse, die durch 4 teilbar ist, ein Double befindet sich an einer Adresse, die durch 8 teilbar ist. Wenn Sie ein Zeichen gefolgt von einem Float deklarieren, werden die meisten Architekturen 3 Bytes auffüllen, aber einige könnten möglicherweise 1 Byte auffüllen. Wenn Sie ein Float deklarieren, gefolgt von einem Zeichen, werden alle Compiler (ich sollte eine Quelle für diese Behauptung hinzufügen, sorry) überhaupt nicht auffüllen.

  • Es gibt keine Garantie dafür, dass der Compiler kein zusätzliches Padding einfügt, also können Sie es nicht sein sicher Es funktioniert, es sei denn, Sie verwenden ein Pack-Pragma oder ähnliches.

    – jalf

    16. September 2009 um 10:01 Uhr

  • Ich habe noch nie einen Compiler gesehen, der Padding für Strukturen mit natürlicher Ausrichtung eingefügt hat. VC++ 6.0, 2003, 2005, 2008, Metrowerks für PPC, Metrowerks für HC12, gcc für ARM, gcc 2.98-3.x für PowerPC, gcc 3.x-4.x für x86, SDCC für 8051, Crossworks für MSP430. Ich würde mich sehr über ein Gegenbeispiel oder eine gute Begründung dafür freuen, warum dies so ist.

    – KeyserSoze

    16. September 2009 um 20:27 Uhr

  • Wenn Sie ein Pack-Pragma auf Strukturen anwenden, die nicht bereits über eine natürliche Ausrichtung verfügen, treten häufig schädliche Nebenwirkungen auf. Wenn Sie z. B. auf PowerPC falsch ausgerichtete Floats haben, tritt eine Hardware-Ausnahme auf. Der Hardware-Handler kann den Prozessor zurücksetzen (üblich bei eingebetteten Apps) oder das Problem in der Software behandeln (was SLOOOOW ist). In beiden Fällen kann Ihnen die Verwendung eines Pack-Pragmas nur schaden, Sie möchten die Struktur auf jeden Fall so definieren, dass sie eine natürliche Ausrichtung hat, und kein Pack verwenden, damit es auf allen Plattformen gleich funktioniert.

    – KeyserSoze

    16. September 2009 um 20:28 Uhr

C und C++ sind unterschiedliche Sprachen, aber es war schon immer die Absicht von C++, dass Sie eine Implementierung haben können, die beide Sprachen binärkompatibel unterstützt. Da es sich um verschiedene Sprachen handelt, ist es immer ein Detail der Compiler-Implementierung, ob dies tatsächlich unterstützt wird. Typischerweise unterstützen Anbieter, die sowohl einen C- als auch einen C++-Compiler (oder einen einzelnen Compiler mit zwei Modi) bereitstellen, die vollständige Kompatibilität für die Übergabe POD-Strukturen (und Hinweise auf POD-Strukturen) zwischen C++-Code und C-Code.

Oft wird die Garantie durch bloßes Vorhandensein eines benutzerdefinierten Konstruktors gebrochen, obwohl Sie manchmal einen Zeiger auf ein solches Objekt an eine C-Funktion übergeben können, die einen Zeiger auf a erwartet struct mit und identischer Datenstruktur und es wird funktionieren.

Kurz gesagt: Überprüfen Sie Ihre Compiler-Dokumentation.

Benutzer-Avatar
Adisak

Verwenden Sie in C und C++ dasselbe “struct”. Wenn Sie Methoden in der C++-Implementierung hinzufügen möchten, können Sie die Struktur erben, und die Größe sollte gleich sein, solange Sie keine Datenelemente oder virtuellen Funktionen hinzufügen.

Beachten Sie, dass eine leere Struktur oder Datenmember, die leere Strukturen sind, in C und C++ unterschiedliche Größen haben. In C ist sizeof(empty-struct) == 0, obwohl in C99 leere Strukturen nicht erlaubt sein sollen (aber möglicherweise trotzdem als “Compiler-Erweiterung” unterstützt werden). In C++ ist sizeof(empty-struct) != 0 (typischer Wert ist 1).

Benutzer-Avatar
tragomaskhalos

Zusätzlich zu anderen Antworten würde ich sicher sein, keine Zugriffsspezifizierer (öffentlich:, privat: usw.) in Ihre C++-Klasse/Struktur einzufügen. Der IIRC-Compiler darf Blöcke von Member-Variablen entsprechend der Sichtbarkeit neu anordnen, so dass private: int a; pubic: int b; könnte a und b vertauscht bekommen. Siehe zB diesen Link: http://www.embedded.com/design/218600150?printable=true

Ich gebe zu, dass ich verblüfft bin, warum die Definition von POD kein entsprechendes Verbot enthält.

Solange Ihre Klasse nicht einige fortgeschrittene Merkmale ihrer Art aufweist, wie z. B. das Wachsen von etwas Virtuellem, sollte es ziemlich dieselbe Struktur sein.

Außerdem kannst du wechseln Class (was aufgrund der Großschreibung sowieso ungültig ist) zu struct ohne Schaden anzurichten. Abgesehen davon, dass die Mitglieder öffentlich werden (sie sind jetzt privat).

Aber jetzt, wo ich daran denke, dass Sie von Typumwandlung gesprochen haben … Es gibt keine Möglichkeit, sich umzudrehen float hinein long den gleichen Wert darstellen oder umgekehrt, indem der Zeigertyp gecastet wird. Ich hoffe, Sie wollen diese Hinweise nur, um Dinge zu verschieben.

  • Wenn Sie struct in class ändern, wird die nur Der Effekt besteht darin, dass die Standardschutzstufe (bis zum ersten expliziten Aufruf von public:, private: oder protected:) öffentlich statt privat wird.

    – bdonlan

    15. September 2009 um 20:47 Uhr

  • bdonlan, ja, das habe ich erwähnt. Aber man sollte die emotionale Seite des Deals nicht unterschätzen 😉

    – Michael Krelin – Hacker

    15. September 2009 um 20:49 Uhr

  • Float-Version ist ein völlig anderer Fall (OpenGL) und int ist für Windows (Punktstruktur). und Klassenbeispiel sollte public: at top haben. Ich werfe es nur als Probe.

    – Cem Kalyoncu

    15. September 2009 um 20:59 Uhr

  • okay, wollte nur sichergehen, dass du es nicht versuchst Konvertieren von Float auf diese Weise.

    – Michael Krelin – Hacker

    15. September 2009 um 21:12 Uhr

1018970cookie-checkC++-Klassen- oder Struct-Kompatibilität mit C-Struct

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy