Diese Notation vor der Funktion wird als "Aufrufkonvention" bezeichnet. Es gibt an, wie (auf einer niedrigen Ebene) der Compiler Eingabeparameter an die Funktion übergeben und ihre Ergebnisse abrufen wird, sobald sie ausgeführt wurden.
Es gibt viele verschiedene Aufrufkonventionen, die beliebtesten sind stdcall
und cdecl
.
Man könnte denken, dass es nur eine Möglichkeit gibt, dies zu tun, aber in Wirklichkeit gibt es Dutzende von Möglichkeiten, wie man eine Funktion aufrufen und Variablen ein- und ausleiten kann. Sie können die Eingabeparameter auf einem Stapel platzieren (drücken, drücken, drücken, um anzurufen, Pop, Pop, Pop, um Eingabeparameter zu lesen). Oder vielleicht würden Sie sie lieber in Registern stecken (das ist fastcall
- es versucht, einige der Eingabeparameter in Registern für die Geschwindigkeit anzupassen).
Aber was ist dann mit der Bestellung? Schiebst du sie von links nach rechts oder von rechts nach links? Was ist mit dem Ergebnis - es gibt immer nur eins (unter der Annahme, dass keine Bezugsparameter vorhanden sind), also platzieren Sie das Ergebnis auf dem Stapel, in einem Register, an einer bestimmten Speicheradresse?
Nehmen wir an, Sie verwenden den Stack für die Kommunikation - wer ist der Job, um den Stack nach dem Aufruf der Funktion tatsächlich zu löschen - den Anrufer oder den Angerufenen?
Wie wäre es, den Inhalt von (bestimmten) CPU-Registern zu sichern und dann wiederherzustellen - sollte der Aufrufer das tun, oder wird der Angerufene garantieren, dass er alles so zurückgibt, wie er war?
Die beliebteste Aufrufkonvention (bei weitem) ist cdecl
. Dies ist die Standard-Aufrufkonvention in C und C ++. Die WIN32-API verwendet stdcall
, was bedeutet, dass jeder Code, der die WIN32-API aufruft, für diese Funktionsaufrufe stdcall
verwenden muss (was eine weitere beliebte Wahl darstellt).
fastcall
ist ein bisschen komisch - Leute, die für viele Funktionen mit nur einem In / Out-Parameter realisiert werden, das Drücken und Poppen aus einem Speicher-basierten Stack ist ziemlich viel Overhead und macht Funktionsaufrufe ein wenig schwer Die verschiedenen Compiler haben (unterschiedliche) Aufrufkonventionen eingeführt, die einen oder mehrere Parameter in Registern platzieren, bevor der Rest für eine bessere Leistung in den Stapel gelegt wird. Das Problem ist, dass nicht alle Compiler dieselben Regeln für das verwenden, was wo geht und wer was mit fastcall
tut, und als Ergebnis müssen Sie vorsichtig sein, wenn Sie es verwenden, weil Sie nie wissen werden, wer was tut. Schließlich finden Sie Ist fastcall wirklich schneller? für Informationen über fastcall
Leistungsvorteile.
Kompliziertes Zeug.
Wichtiger Hinweis: Fügen Sie keine Aufrufkonventionen hinzu oder ändern Sie sie nicht, wenn Sie genau nicht wissen, was Sie tun, denn wenn der Anrufer und der Angerufene nicht einverstanden sind Bei der Aufrufkonvention werden Sie wahrscheinlich mit Stack-Korruption und einem Segfault enden. Dies passiert normalerweise, wenn Sie die Funktion in einer DLL / shared library aufrufen und ein Programm geschrieben wird, das davon abhängt, dass die DLL / SO / dylib eine bestimmte Aufrufkonvention ist (zB cdecl
), dann wird die Bibliothek mit a neu kompiliert verschiedene Aufrufkonventionen (zB fastcall
). Jetzt kann das alte Programm nicht mehr mit der neuen Bibliothek kommunizieren.
Konventionen mit dem Titel fastcall wurden nicht standardisiert und wurden je nach Compilerhersteller unterschiedlich implementiert. In der Regel übergeben schnelle Aufrufkonventionen ein oder mehrere Argumente in Registern, wodurch die Anzahl der für den Aufruf erforderlichen Speicherzugriffe reduziert wird.
Tags und Links visual-c++ calling-convention fastcall