2009-02-26 18 views
22

Was ist der Unterschied zwischen einer statischen Elementfunktion und einer externen "C" -Verbindungsfunktion? Zum Beispiel muss ich bei der Verwendung von "makecontext" in C++ einen Zeiger an die Funktion übergeben. Google empfiehlt, externe C-Verknüpfungen zu verwenden, da "makecontext" C ist. Aber ich habe herausgefunden, dass auch statische Arbeiten verwendet werden. Bin ich glücklich oder ... geradestatisch vs extern "C"/"C++"

class X { 
    public: 
    static void proxy(int i) {} 
} 
makecontext(..., (void (*)(void)) X::proxy, ...); 

vs

extern "C" void proxy(int i) {} 
makecontext(..., (void (*)(void)) proxy, ...); 

EDIT: Können Sie einen Compiler oder Architektur zeigen, wo die statische Elementversion nicht funktioniert (und es ist kein Bug im Compiler) ?

+0

'Es tut mir leid, aber ich bin immer noch nicht überzeugt '... von was? die Tatsache, dass der Standard autoritativer ist als das zufällige implementierungsdefinierte Verhalten einiger Compiler? –

+0

Dies ist ein alter Beitrag (vor 8 Jahren heute) Mein Punkt war zu der Zeit so etwas wie IMHO, wenn sich jede existierende Implementierung vom Standard unterscheidet dann solltest du vielleicht eine Frage stellen ob es der Standard ist der falsch ist. Ich suchte nach Beispielen für Plattformen, auf denen es nicht funktioniert. –

+0

Fair genug.Es ist natürlich nicht unüblich, dass die C- oder C++ - Standards unbeabsichtigte Konsequenzen enthalten, die von allen existierenden Compilern ignoriert werden. Das ist momentan mein Favorit: http://StackOverflow.com/a/42335543/2757035 Aber in diesem Fall denke ich, dass der Standard ziemlich klar sagt, was es bedeutet, und Implementierungen könnten ihr Verhalten jederzeit ändern, wenn es solche gibt ein Vorteil. –

Antwort

33

Ja, Sie haben nur Glück :) Das externe "C" ist eine Sprache Verknüpfung für die C-Sprache, die jeder C++ - Compiler unterstützt, neben extern "C++", die die Standardeinstellung ist. Compiler können andere Sprachverbindungen unterstützen. GCC unterstützt zum Beispiel extern "Java", was eine Schnittstelle mit Java-Code ermöglicht (obwohl das ziemlich umständlich ist).

extern "C" teilt dem Compiler mit, dass Ihre Funktion durch C-Code aufgerufen werden kann. Das kann, muss aber nicht, die entsprechende Aufrufkonvention und den entsprechenden C-Namen-Mangling (manchmal auch "Dekoration" genannt) beinhalten, abhängig von der Implementierung. Wenn Sie eine statische Member-Funktion haben, ist die Aufrufkonvention dafür die Ihres C++ - Compilers. Oft sind sie die gleichen wie für den C-Compiler dieser Plattform - also habe ich gesagt, dass Sie nur Glück haben. Wenn Sie einen C-API haben und Sie einen Funktionszeiger übergeben, besser gesagt immer eine auf eine Funktion, mit extern „C“ erklärt wie

extern "C" void foo() { ... } 

Auch wenn der Funktion Zeigertyp nicht die Verknüpfung Spezifikation enthält, sondern sieht aus wie

void(*)(void) 

die Verknüpfung ist ein integraler Bestandteil des Typs - Sie kann es einfach nicht ausdrücken direkt ohne typedef:

extern "C" typedef void(*extern_c_funptr_t)(); 

der Comeau C++ Compiler, im strikten Modus , wird beispielsweise dann ein Fehler ausgegeben, wenn Sie versuchen, die Adresse der externen "C" -Funktion von oben einer (void(*)()) zuzuweisen, da dies ein Zeiger auf eine Funktion mit C++ - Verknüpfung ist.

+1

Um zu Litbs Antwort hinzuzufügen, sollten Sie über die Aufrufkonventionen bei Wikipedia lesen - http://en.wikipedia.org/wiki/X86_calling_conventions. extern C impliziert cdecl Aufrufkonvention; Ihr Compiler verwendet denselben für statische Elementfunktionen. Andere Compiler können auch andere auswählen. –

+0

@Comeau Compiler, ist es ein Fehler oder eine Warnung, die es ausgibt? –

+0

Helltone, versuchen Sie es http://www.comeaucomputing.com/tryitout/ es sagt: '"ComeauTest.c", Zeile 4: Fehler: ein Wert vom Typ "void (*)() C" kann nicht verwendet werden initialisiere eine Entität vom Typ "void (*)()" ' –

4

extern "C" deaktiviert den C++ - Compiler Name Mangling (die für die Überladung erforderlich ist).

Wenn Sie eine Funktion in A.cpp als static deklarieren, kann sie nicht von B.cpp gefunden werden (sie ist von C übrig geblieben und hat dieselbe Wirkung wie eine Funktion in einem anonymen Namespace).

+0

Dies beantwortet meine Frage nicht –

+0

Es kann auch die Aufrufkonvention ändern. –

+0

Hinweis: Das OP sprach über statische _methods_ ("Mitgliedsfunktionen"), nicht _global_ Funktionen mit statischer Verknüpfung. –

5

Beachten Sie, dass extern C die empfohlene Art der C/C++ Interoperabilität ist. Here spricht der Meister darüber. Um die Antwort von eduffy hinzuzufügen: Beachten Sie, dass statische Funktionen und Variablen im globalen Namespace veraltet sind. Verwenden Sie mindestens einen anonymen Namespace.

Zurück zu extern C: Wenn Sie kein externes C verwenden, müssen Sie den genauen Namen kennen und verwenden. Das ist viel mehr ein Schmerz.

+0

Hinweis: das OP war über statische _methoden_ ("member functions") sprechen, nicht _global_ funktioniert mit statischer Verknüpfung. –

2

Das meiste, was extern "C" tut, ist weitgehend compilerabhängig. Viele Plattformen ändern die Namen-Mangling- und Aufrufkonvention basierend auf der Deklaration, aber keine davon wird vom Standard spezifiziert. Das einzige, was der Standard erfordert, ist, dass der Code im Block von C-Funktionen aufgerufen werden kann.Was Ihre konkrete Frage, sagt der Standard:

Two function types with different language linkages are distinct types even if they are otherwise identical.

Das bedeutet extern "C" void proxy(int i) {} und /*extern "C++"*/void proxy(int i) {} verschiedene Typen haben, und als Ergebnis Zeiger auf diese Funktionen auch verschiedene Typen haben würde. Der Compiler nicht ausfällt Code aus dem gleichen Grund wäre es nicht ein großes Stück Arbeit wie fehlschlagen:

int *foo = (int*)50; 
makecontext(..., (void (*)(void)) foo, ...); 

Dieser Code auf einige Plattform funktionieren könnte, aber das bedeutet nicht, es auf einem anderen arbeiten Plattform (auch wenn der Compiler vollständig standardkonform war). Sie profitieren davon, wie Ihre Plattform funktioniert, was in Ordnung sein kann, wenn Sie nicht daran interessiert sind, tragbaren Code zu schreiben.

Wie bei statischen Elementfunktionen müssen sie keinen this Zeiger haben, damit der Compiler sie als Nicht-Member-Funktion behandeln kann. Auch hier ist das Verhalten plattformspezifisch.

+0

Gute Antwort, aber Sie vermissen den Punkt meiner Frage völlig. Meine Frage betrifft den Unterschied zwischen der externen "C" -Funktion und einer * statischen Member * -Funktion. –

2

Generell

Speicherklassen:

Speicherklassen verwendet werden Dauer und Umfang einer Variablen oder Kennung anzuzeigen.

Dauer:

Dauer gibt die Lebensdauer einer Variablen.

Scope:

Scope zeigt die Sichtbarkeit der Variablen.

statische Speicherklasse:

Die statische Speicherklasse wird verwendet, um einen Identifikator zu deklarieren, die eine lokale Variable entweder auf eine Funktion oder eine Datei und das vorhanden ist, und behält seinen Wert nach Kontrolle von gelangt, wo es war erklärt. Diese Speicherklasse hat eine Dauer, die dauerhaft ist. Eine von dieser Klasse deklarierte Variable behält ihren Wert von einem Aufruf der Funktion zum nächsten. Der Umfang ist lokal. Eine Variable ist nur durch die Funktion bekannt, in der sie deklariert ist, oder wenn sie global in einer Datei deklariert ist, sie ist nur bekannt oder wird nur von den Funktionen in dieser Datei gesehen. Diese Speicherklasse garantiert, dass die Deklaration der Variablen auch die Variable auf Null oder alle Bits initialisiert.

Externe Speicherklasse:

Die externe Speicherklasse wird verwendet, um eine globale Variable zu deklarieren, die in einem Programm alle Funktionen sind bekannt für die Funktionen in einer Datei und in der Lage bekannt werden. Diese Speicherklasse hat eine Dauer, die dauerhaft ist. Jede Variable dieser Klasse behält ihren Wert bei, bis sie durch eine andere Zuweisung geändert wird. Der Umfang ist global. Eine Variable kann von allen Funktionen innerhalb eines Programms erkannt oder gesehen werden.