Stdcall und Cdecl
Gibt es (unter anderem) zwei Arten von Aufrufkonventionen - stdcall und cdecl. Ich habe einige Fragen an Sie:
- Wenn eine cdecl-Funktion aufgerufen wird, wie wird ein Anrufer
wissen, wenn es frei werden sollte, bis der stack ? Auf den Ruf Website, hat die
Anrufer wissen, ob die Funktion aufgerufen wird, ist eine cdecl oder stdcall
Funktion ? Wie funktioniert es ? Wie funktioniert die Anrufer wissen, wenn es sollte
frei bis der stack oder nicht ? Oder ist es der Linker der Verantwortung ? - Wenn eine Funktion, die deklariert ist als stdcall ruft eine Funktion(die
eine Aufruf-Konvention als cdecl), oder Umgekehrt, würde
dies unangemessen ? - Im Allgemeinen können wir sagen, dass die call-schneller - oder cdecl
stdcall ?
InformationsquelleAutor der Frage Rakesh Agarwal | 2010-08-04
Du musst angemeldet sein, um einen Kommentar abzugeben.
Raymond Chen gibt einen schönen überblick über das, was
__stdcall
und__cdecl
.(1) Der Anrufer "weiß" zum bereinigen des Stacks nach Aufruf einer Funktion, da weiß der compiler die Aufrufkonvention der Funktion und generiert den erforderlichen code.
Es ist möglich Fehlanpassung der Aufrufkonventionwie diese:
So viele code-Beispiele verstehen das falsch, es ist auch nicht lustig. Es soll so sein:
Jedoch, vorausgesetzt der Programmierer nicht ignorieren compiler-Fehler, der compiler generiert den code, der benötigt wird, um sauber in den stack richtig, da es weißt, die Aufrufkonventionen von Funktionen beteiligt.
(2) in Beide Richtungen funktionieren sollte. In der Tat, das passiert Recht Häufig, zumindest in code, der im zusammenspiel mit der Windows-API, da
__cdecl
ist der Standardwert für C-und C++ - Programme nach Visual C++ - compiler und die WinAPI-Funktionen verwenden Sie die__stdcall
- übereinkommens.(3) sollte Es keinen wirklichen performance-Unterschied zwischen den beiden.
InformationsquelleAutor der Antwort In silico
In CDECL Argumente auf dem Stapel in der revers, um die Anrufer-löscht den stack und das Ergebnis wird zurückgegeben, Prozessor via registry (später werde ich es nennen "registrieren"). In STDCALL es ist ein Unterschied, der Anrufer doeasn nicht klar, den Stapel, der calle tun.
Werden Sie gefragt, welches ist schneller. Niemand. Sie sollten systemeigene Aufrufkonvention so lange wie Sie können. Ändern Konvention nur, wenn es keinen Ausweg gibt, bei der Verwendung von externen Bibliotheken erfordert eine bestimmte Konvention verwendet werden.
Daneben gibt es weitere Konventionen, die compiler können wählen, als Standard ein, d.h. Visual C++ - compiler verwendet FASTCALL das ist theoretisch schneller, weil mehr umfangreiche Verwendung von Prozessor-Registern.
In der Regel müssen Sie eine richtige Aufrufkonvention Signatur-callback-Funktionen übergeben wird, um eine externe Bibliothek, d.h. den Rückruf
qsort
von der C-Bibliothek muss CDECL (wenn der compiler standardmäßig verwendet andere Konvention, dann müssen wir markieren den Rückruf als CDECL) oder diverse WinAPI Rückrufe werden muss STDCALL (ganze WinAPI ist STDCALL).Anderen üblichen Fall sein kann, wenn Sie speichern Verweise auf externe Funktionen, d.h. erstellen Sie einen Zeiger auf WinAPI-Funktion seine Art definition markiert werden muss, mit STDCALL.
- Und unterhalb ist ein Beispiel dafür, wie weiß der compiler:
CDECL:
STDCALL:
InformationsquelleAutor der Antwort adf88
Bemerkte ich einen Beitrag, die sagen, dass es egal ist, wenn Sie anrufen ein
__stdcall
aus einer__cdecl
oder Umgekehrt. Es funktioniert.Der Grund: mit der
__cdecl
die Argumente, die übergeben werden, um die genannten Funktionen zu entfernen form der stack der aufrufenden Funktion, in__stdcall
die Argumente vom stack entfernt von der aufgerufenen Funktion. Wenn Sie rufen eine__cdecl
Funktion mit einem__stdcall
der stack ist nicht gereinigt, überhaupt, so dass schließlich, wenn die__cdecl
verwendet eine gestapelte basierte Referenz für Argumente oder return-Adresse, wird die Nutzung der alten Daten auf das aktuelle stack-pointer. Wenn Sie rufen eine__stdcall
Funktion aus einer__cdecl
die__stdcall
- Funktion säubert die Argumente auf den stack und dann den__cdecl
Funktion tut es wieder, möglicherweise das entfernen der Aufruf von Funktionen, die Informationen zurückgeben.Microsoft-Konvention für C versucht um dies zu umgehen, indem mangeln die Namen. Ein
__cdecl
Funktion ist mit einem Unterstrich als Präfix. Ein__stdcall
Funktion Präfixe, die mit einem underscore und Suffix mit einem at-Zeichen "@" und die Anzahl der bytes an, die entfernt werden. ZB__cdecl
f(x) verknüpft ist, als_x
__stdcall f(int x)
verbunden ist als_f@4
wosizeof(int)
4 bytes)Wenn es Ihnen gelingt, vorbei an der linker, genießen Sie die debugging-Chaos.
InformationsquelleAutor der Antwort Lee Hamilton
Möchte ich verbessern @adf88 Antwort. Ich fühle, dass pseudocode für die STDCALL spiegeln nicht die Art und Weise, wie es passiert in der Realität. 'a', 'b' und 'c' sind nicht aufgetaucht, aus dem Stapel in der Funktion Körper. Stattdessen sind Sie knallte durch die
ret
Unterricht (ret 12
würde in diesem Fall verwendet werden), die auf einen Schlag springt wieder zurück auf den Anrufer und gleichzeitig erscheint 'a', 'b' und 'c' vom Stapel.Hier ist meine version korrigiert nach meinem Verständnis:
STDCALL:
InformationsquelleAutor der Antwort golem
Der Anrufer und der angerufene müssen die gleiche Konvention an die Stelle der Aufruf - das ist der einzige Weg, es könnte zuverlässig arbeiten. Sowohl der Anrufer als auch der angerufene Folgen einem vordefinierten Protokoll - wer zum Beispiel braucht, um sauber in den stack. Wenn Konventionen mismatch, während Ihr Programm läuft in undefiniertem Verhalten - wahrscheinlich nur stürzt spektakulär.
Dies ist nur nötig, pro Aufruf-Website - der aufrufende code kann selbst eine Funktion sein, die mit jedem Aufruf-Konvention.
Sie sollten nicht bemerken keinen Unterschied in der Leistung zwischen diesen Konventionen. Wenn das zum problem wird, müssen Sie in der Regel weniger telefonieren - zum Beispiel, ändern Sie den Algorithmus.
InformationsquelleAutor der Antwort sharptooth
Es ist in der Funktion angegebenen Typ. Wenn Sie eine Funktion Zeiger, davon ausgegangen zu sein, cdecl, wenn Sie nicht ausdrücklich stdcall. Dies bedeutet, dass, wenn Sie eine stdcall-Zeiger und eine cdecl-pointer können Sie nicht umtauschen. Die beiden Funktionstypen können einander aufrufen, ohne Probleme, es ist nur immer eine geben, wenn Sie erwarten, dass die anderen. Wie für die Geschwindigkeit, die Sie beide führen die gleichen Rollen, nur sehr geringfügig statt, es ist wirklich irrelevant.
InformationsquelleAutor der Antwort Puppy
Diese Dinge sind Compiler - und Plattform-spezifisch. Weder der C noch der C++ - standard nichts sagen, über den Aufruf-Konventionen außer für
extern "C"
in C++.Den Anrufer kennt die Aufrufkonvention der Funktion an und verarbeitet den Anruf entsprechend.
Ja.
Es ist Teil der Deklaration der Funktion.
Den Anrufer kennt die Aufrufkonventionen und entsprechend handeln können.
Nein, die Aufruf-Konvention ist Teil einer Funktion, in dem die Erklärung so weiß der compiler alles, was er wissen muss.
Nicht. Warum sollte es?
Weiß ich nicht. Testen Sie es.
InformationsquelleAutor der Antwort sellibitze
Den
cdecl
modifier ist Teil der Funktionsprototyp (oder Funktion Zeiger Typ etc.) also der Anrufer bekommt die info von dort aus und agiert entsprechend.Nein, es ist in Ordnung.
Generell würde ich es unterlassen, solche Aussagen. Die Unterscheidung Angelegenheiten zB. wenn Sie verwenden möchten, va_arg Funktionen. In der Theorie, es könnte sein, dass
stdcall
ist schneller und erzeugt weniger code, weil es erlaubt zu kombinieren knallen die Argumente mit knallen die einheimischen, aber OTOH mitcdecl
Sie können das gleiche tun, auch, wenn Sie klug.Den Aufrufkonventionen, die zum Ziel haben, schneller zu sein in der Regel tun, einige register übergeben.
InformationsquelleAutor der Antwort jpalecek
Aufrufkonventionen haben nichts zu tun mit der C/C++ Programmiersprachen und sind eher Besonderheiten auf, wie ein compiler implementiert, der angegebenen Sprache. Wenn Sie ständig den gleichen compiler, und Sie müssen nie sorgen zu machen über den Aufruf-Konventionen.
Aber manchmal wollen wir binären code kompiliert, die von unterschiedlichen Compilern zu inter-richtig. Wenn wir das tun, müssen wir definieren die so genannte Application Binary Interface (ABI). Das ABI legt fest, wie der compiler wandelt den C/C++ Quelltext in Maschinen-code. Dies beinhaltet die Aufrufkonventionen, name mangling, und der v-Tisch-layout. cdelc und stdcall sind zwei unterschiedliche Aufrufkonventionen Häufig auf x86-Plattformen.
Indem Sie die Informationen über die Aufruf-Konvention in den Quellcode-header, der compiler wissen, welcher code generiert werden soll zu inter-agieren korrekt mit der angegebenen ausführbaren Datei.
InformationsquelleAutor der Antwort doron