Forum: Compiler & IDEs C und C++ kompatibilität


von Aabeku K. (aabeku)


Lesenswert?

Hi,

ich bin etwas neu in C++. In C bin ich eigentlich recht flüssig. Nun zu 
meiner Frage.

Kann ich in C++ ohne weiteres Pointer an C übergeben oder muss diese 
Funktion, Variable usw... bestimmte Bedingungen erfüllen?

Was ich bisher zu wissen glaube:

- Klassen können logischerweise nicht direkt übergeben werden. Als void* 
ist das aber möglich. Hier ist aber zu beachten, dass bestimmte 
Funktionen wie memcpy nur bei POD-Klassen funktionieren.

- Als static "C" deklarierte Funktionen können direkt im C-Code 
verwendet werden. Einfache Variablen und Funktionen können also mit 
etwas Aufwand an C übergeben werden.

Ich habe widersprüchliche Dinge gelesen über das Übergeben von 
Klassenmember-Pointern. Deshalb bitte ich hier um Klarstellung. Kann ich 
nun einfach einen Pointer auf einen Klassenmember übergeben oder geht 
das nur unter bestimmten Vorraussetzungen? Wenn ja welche 
Voraussetzungen muss ich beachten?

Hoffe ihr könnt mir da weiterhelfen.

MFG

von Harald K. (kirnbichler)


Lesenswert?

Aabeku K. schrieb:
> Deshalb bitte ich hier um Klarstellung. Kann ich
> nun einfach einen Pointer auf einen Klassenmember übergeben oder geht
> das nur unter bestimmten Vorraussetzungen?

Das Klassenmember muss ein Datentyp sein, mit dem C etwas anfangen kann.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Aabeku K. schrieb:
> - Als static "C" deklarierte Funktionen

Du meinst 'extern "C"'. ja? Dann stimmt es.

Aabeku K. schrieb:
> Kann ich
> nun einfach einen Pointer auf einen Klassenmember übergeben

Ja, das ist kein Problem. Das wird sehr oft so gemacht.

Aabeku K. schrieb:
> Als void*
> ist das aber möglich.

Ja. Du kannst auch einen Zeiger auf eine Klasse z.B. nach void* 
umcasten, an C übergeben, dann aus C wieder zurück bekommen, zurück auf 
den Klassentyp casten, und normal weiter verwenden. Das wird oft gemacht 
bei Callbacks aus C-Code mit dem typischen "void* user_data" -Argument.

von Oliver S. (oliverso)


Lesenswert?

Aabeku K. schrieb:
> - Klassen können logischerweise nicht direkt übergeben werden. Als void*
> ist das aber möglich. Hier ist aber zu beachten, dass bestimmte
> Funktionen wie memcpy nur bei POD-Klassen funktionieren.

Da C keine Klassen kennt, kannst du in C mit einem pointer auf eine 
C++-Klasse nur sehr wenig anfangen, egal, wohin du den auch castest. 
Eine C++-Klasse über einen pointer in C zu kopieren, wäre wohl ein nur 
in der allergrößten Not anzuwendender Hack.

Aabeku K. schrieb:
> Ich habe widersprüchliche Dinge gelesen über das Übergeben von
> Klassenmember-Pointern. Deshalb bitte ich hier um Klarstellung. Kann ich
> nun einfach einen Pointer auf einen Klassenmember übergeben oder geht
> das nur unter bestimmten Vorraussetzungen? Wenn ja welche
> Voraussetzungen muss ich beachten?

Neben dem schon gesagten muß man dabei, wie überall beim hantieren mit 
Pointern, auf deren Gültigkeit bzw. die Lebensdauer der Instanz dazu 
achten.

Oliver

von Aabeku K. (aabeku)


Lesenswert?

Kann ich auch einen Pointer von einer überladenen Funktion oder einer 
virtuellen Funktion übergeben? Also z.B.:
1
class example{
2
    [...]
3
    void foo(int data);
4
    void foo(char name);
5
6
    virtual void vfoo(int data);
7
};

Können diese Funktionen innerhalb des C-Codes dann auch 
aufgerufen/verwendet werden oder geht das wiederum nur im C++-Code?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Aabeku K. schrieb:
> Können diese Funktionen innerhalb des C-Codes dann auch
> aufgerufen/verwendet werden

Nein, du kannst keine Member-Funktionen aus C-Code heraus direkt 
aufrufen, egal ob virtual oder nicht. Du kannst aber einfach eine 
globale Funktion (mit extern "C") erstellen und von dort die 
Member-Funktion aufrufen.

Von statischen Member-Funktionen kannst du aber einen Funktionszeiger 
erstellen, nach C übergeben und dort aufrufen. Direkt geht es aber auch 
nicht.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
> Da C keine Klassen kennt, kannst du in C mit einem pointer auf eine
> C++-Klasse nur sehr wenig anfangen, egal, wohin du den auch castest.
> Eine C++-Klasse über einen pointer in C zu kopieren, wäre wohl ein nur
> in der allergrößten Not anzuwendender Hack.

Nö, das ist eigentlich was ganz normales. Man kann sich den Zeiger 
merken, d.h. er wird in einer C++-Funktion erzeugt, auf der C-Seite 
bekommt man den Zeiger und kann ihn dann später nutzen, um damit eine 
andere C++-Funktion aufzurufen.

Niklas G. schrieb:
> Aabeku K. schrieb:
>> Können diese Funktionen innerhalb des C-Codes dann auch
>> aufgerufen/verwendet werden
>
> Nein, du kannst keine Member-Funktionen aus C-Code heraus direkt
> aufrufen, egal ob virtual oder nicht. Du kannst aber einfach eine
> globale Funktion (mit extern "C") erstellen und von dort die
> Member-Funktion aufrufen.

Und dann das Objekt eben per void* übergeben.

> Von statischen Member-Funktionen kannst du aber einen Funktionszeiger
> erstellen, nach C übergeben und dort aufrufen. Direkt geht es aber auch
> nicht.

Das funktioniert zwar bei allen mir bekannten Compilern, ist aber 
offiziell eigentlich nicht erlaubt. Von C aus dürfen nur Funktionen 
aufgerufen werden, die als extern "C" definiert sind, und das ist bei 
statischen Memberfunktionen nicht möglich.

von Harald K. (kirnbichler)


Lesenswert?

Rolf M. schrieb:
> Von C aus dürfen nur Funktionen
> aufgerufen werden, die als extern "C" definiert sind

Wie kommst Du auf diese Idee?

Direkt (ohne Funktionspointer) lassen sie sich wegen ihrer 
Linkersignatur nicht anders verwenden, aber warum sollte die Verwendung 
statischer C++-Member via Funktionspointer "illegal" sein?

Das halte ich für ziemlich ausgeschlossen, denn dann wäre schlagartig 
eine irrwitzig große Menge von Code nicht mehr verwendbar.

von Rolf M. (rmagnus)


Lesenswert?

Harald K. schrieb:
> Rolf M. schrieb:
>> Von C aus dürfen nur Funktionen
>> aufgerufen werden, die als extern "C" definiert sind
>
> Wie kommst Du auf diese Idee?

Das steht so im C++-Standard.

> Direkt (ohne Funktionspointer) lassen sie sich wegen ihrer
> Linkersignatur nicht anders verwenden, aber warum sollte die Verwendung
> statischer C++-Member via Funktionspointer "illegal" sein?

Weil extern "C" sich nicht nur auf die Signatur bezieht, sondern auf 
alle Aspekte eines Funktionsaufrufs, also auch Aufrufkonventionen, z.B. 
wie Parameter übergeben werden. Ob so ein Aufruf ohne extern "C" 
trotzdem funktioniert, hängt also letztlich davon ab, ob das vom 
Compiler umgesetzte ABI für C und für C++ im Bezug auf Funktionaufrufe 
gleich ist.

> Das halte ich für ziemlich ausgeschlossen, denn dann wäre schlagartig
> eine irrwitzig große Menge von Code nicht mehr verwendbar.

Das ist nicht schlagartig so, sondern war schon immer so.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Rolf M. schrieb:
> Oliver S. schrieb:
>> Da C keine Klassen kennt, kannst du in C mit einem pointer auf eine
>> C++-Klasse nur sehr wenig anfangen, egal, wohin du den auch castest.
>> Eine C++-Klasse über einen pointer in C zu kopieren, wäre wohl ein nur
>> in der allergrößten Not anzuwendender Hack.
>
> Nö, das ist eigentlich was ganz normales. Man kann sich den Zeiger
> merken, d.h. er wird in einer C++-Funktion erzeugt, auf der C-Seite
> bekommt man den Zeiger und kann ihn dann später nutzen, um damit eine
> andere C++-Funktion aufzurufen.

Mit einem pointer auf eine C++-Klasse willst du aus C eine andere 
C++-Funktion aufrufen? Oder meinst du, du gibst den unverändert an C++ 
zurück, und kannst den dann da ganz normal nutzen?

Letzteres wäre völlig normal.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
>> Nö, das ist eigentlich was ganz normales. Man kann sich den Zeiger
>> merken, d.h. er wird in einer C++-Funktion erzeugt, auf der C-Seite
>> bekommt man den Zeiger und kann ihn dann später nutzen, um damit eine
>> andere C++-Funktion aufzurufen.
>
> Mit einem pointer auf eine C++-Klasse willst du aus C eine andere
> C++-Funktion aufrufen? Oder meinst du, du gibst den unverändert an C++
> zurück, und kannst den dann da ganz normal nutzen?
>
> Letzteres wäre völlig normal.

Ja, das meinte ich. Ich schrieb ja, dass es auf der C-Seite nur darum 
geht, sich den Zeiger zu merken, um ihn später wieder an die C++-Seite 
übergeben zu können.

von K. M. (kmj)



Lesenswert?

Hier eine Übersicht über die ABI verschiedener Compiler auf x86 & ARM.

von Harald K. (kirnbichler)


Lesenswert?

Rolf M. schrieb:
> Das steht so im C++-Standard.

Magst Du das präzisieren?

von Oliver S. (oliverso)


Lesenswert?

Rolf M. schrieb:
> Ja, das meinte ich. Ich schrieb ja, dass es auf der C-Seite nur darum
> geht, sich den Zeiger zu merken, um ihn später wieder an die C++-Seite
> übergeben zu können.

Und das meinte ich damit, daß man auf der C-Seite damit nicht viel 
anfangen kann, ausser den wieder zurückzugeben.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
> Rolf M. schrieb:
>> Ja, das meinte ich. Ich schrieb ja, dass es auf der C-Seite nur darum
>> geht, sich den Zeiger zu merken, um ihn später wieder an die C++-Seite
>> übergeben zu können.
>
> Und das meinte ich damit, daß man auf der C-Seite damit nicht viel
> anfangen kann, ausser den wieder zurückzugeben.

Ja, aber du schriebst was von Hacks, die man nur in größter Not anwenden 
sollte, wobei mir nicht klar ist, was du mit "Eine C++-Klasse über einen 
pointer in C zu kopieren" meintest. Möglicherweise hast du dich da auf 
was anderes bezogen und ich habe es missverstanden.

Harald K. schrieb:
> Rolf M. schrieb:
>> Das steht so im C++-Standard.
>
> Magst Du das präzisieren?

Aus Draft N4950:

"Some of the properties associated with an entity with language linkage 
are specific to each implementation and are not described here. For 
example, a particular language linkage might be associated with a 
particular form of representing names of objects and functions with 
external linkage, or with a particular calling convention, etc."

Mit anderen Worten: name-mangling ist nicht das einzige, was da hinein 
spielt. Mit extern "C" kümmert sich der Compiler um alle Unterschiede, 
die es bei Funktionsaufrufen geben könnte, ohne funktioniert's halt nur, 
wenn die calling conventions übereinstimmen.
Übrigens sind ein Zeiger auf eine Funktion, die extern "C" ist und ein 
Zeiger auf eine Funktion ohne extern "C" auch grunsätzlich verschiedene 
Typen. ("Two function types with different language linkages are 
distinct types even if they are otherwise identical.")

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Rolf M. schrieb:
> Ja, aber du schriebst was von Hacks, die man nur in größter Not anwenden
> sollte, wobei mir nicht klar ist, was du mit "Eine C++-Klasse über einen
> pointer in C zu kopieren" meintest.

Das bezog sich auf

Aabeku K. schrieb:
> - Klassen können logischerweise nicht direkt übergeben werden. Als void*
> ist das aber möglich. Hier ist aber zu beachten, dass bestimmte
> Funktionen wie memcpy nur bei POD-Klassen funktionieren.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Ok, dann war es ein Missverständnis, und wir sind uns eigentlich einig.

von Sebastian W. (wangnick)


Lesenswert?

Rolf M. schrieb:
> Übrigens sind ein Zeiger auf eine Funktion, die extern "C" ist und ein
> Zeiger auf eine Funktion ohne extern "C" auch grunsätzlich verschiedene
> Typen.

Und wie schreibt man diese verschiedenen Typen hin?

LG, Sebastian

von Rolf M. (rmagnus)


Lesenswert?

Noch ein Zitat aus dem genannten Draft:
"Because the language linkage is part of a function type, when 
indirecting through a pointer to C function, the function to which the 
resulting lvalue refers is considered a C function."

Sebastian W. schrieb:
> Und wie schreibt man diese verschiedenen Typen hin?

Beispiel aus dem Draft:
1
extern "C" typedef void FUNC_c();
2
class C {
3
void mf1(FUNC_c*); // the function mf1 and its type have C++ language linkage;
4
// the parameter has type “pointer to C function”
5
FUNC_c mf2; // the function mf2 and its type have C++ language linkage
6
static FUNC_c* q; // the data member q has C++ language linkage;
7
// its type is “pointer to C function”
8
};
9
extern "C" {
10
class X {
11
void mf(); // the function mf and its type have C++ language linkage
12
void mf2(void(*)()); // the function mf2 has C++ language linkage;
13
// the parameter has type “pointer to C function”
14
};
15
}

von Falk S. (falk_s831)


Lesenswert?

Aabeku K. schrieb:
> Ich habe widersprüchliche Dinge gelesen über das Übergeben von
> Klassenmember-Pointern. Deshalb bitte ich hier um Klarstellung. Kann ich
> nun einfach einen Pointer auf einen Klassenmember übergeben oder geht
> das nur unter bestimmten Vorraussetzungen? Wenn ja welche
> Voraussetzungen muss ich beachten?

Wie oben genannt, für static gelinkte Klassenfunktionen kein Problem, 
mit extern "C"-Wrapper fürs Name-Mangling und Konventionen (falls 
nötig).

Bei normalen Member-Funktionen wird's glaube komplizierter. Im 
einfachsten Fall kannste es wie bei der WINAPI-Programmierung üblich, 
das Objekt als void* reingeben wo aber noch der Offset zur 
Memberfunktion mit drauf müsste.

In C++ kannste sowas machen wie:
1
#include <iostream>
2
3
struct Foo
4
{
5
  int a = 123;
6
7
  int meineTolleFunc() const { return a; }
8
};
9
10
int main(int argc, char** argv)
11
{
12
  Foo a;
13
14
  Foo* b = &a;
15
  int (Foo::*fnCallback)() const = &Foo::meineTolleFunc;
16
17
  // zusammensetzung obj + memfn-cb:
18
  std::cout << (b->*fnCallback)() << std::endl;
19
  return 0;
20
}

Könnte vielleicht nen Versuch wert sein, musst halt immer das Objekt und 
die zugehörige Klassen-relative Callback mit durchschleifen, um die 
aufrufen zu können. Ob du das Zeug dann aus reinem C aus ohne 
C++-Wrapper aufrufen kannst, weiß ich nicht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.