2008-11-18 14 views
119

Ich lerne über Win32-Programmierung und der WinMain Prototyp sieht aus wie:Was ist __stdcall?

int WINAPI WinMain (HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show) 

Ich war verwirrt, was diese WINAPI Kennung und gefunden war:

#define WINAPI  __stdcall 

Was bedeutet das? Ich bin dadurch verwirrt, dass ich nach einem Rückgabetyp überhaupt etwas habe. Was ist __stdcall für? Was bedeutet es, wenn zwischen dem Rückgabetyp und dem Funktionsnamen etwas vorhanden ist?

+1

@AndrewProck Die "Dummy" Änderung war in diesem Fall in Ordnung, aber im Allgemeinen können Sie ' ' s verwenden, um die alberne (und kontraproduktive - Fall in Punkt) 6 Zeichen Minimum zu umgehen. –

Antwort

137

__stdcall ist die für die Funktion verwendete Aufrufkonvention. Dies teilt dem Compiler die Regeln mit, die für das Einrichten des Stacks, das Drücken von Argumenten und das Abrufen eines Rückgabewerts gelten.

Es gibt eine Reihe von anderen Aufrufkonventionen, __cdecl, __thiscall, __fastcall und die wunderbar genannt __naked. __stdcall ist die Standard-Aufrufkonvention für Win32-Systemaufrufe.

Wikipedia deckt die details.

Dies ist hauptsächlich wichtig, wenn Sie eine Funktion außerhalb Ihres Codes aufrufen (z. B. eine OS-API) oder das Betriebssystem Sie anruft (wie hier bei WinMain). Wenn der Compiler die richtige Aufrufkonvention nicht kennt, werden Sie wahrscheinlich sehr seltsame Abstürze bekommen, da der Stack nicht korrekt verwaltet wird.

+8

Siehe diese Frage für ein Beispiel von sehr Starge Abstürzen http://stackoverflow.com/questions/696306/run-time-check-failure-0-loading-queryfullprozessabbildname-from-kernel32-dll – sharptooth

+0

Wenn ich mich nicht irre, Diese Aufrufkonventionen steuern dann, wie der Compiler den Assemblercode erzeugt. Bei der Verbindung mit dem Assembly-Code ist es wichtig, dass die Aufrufkonvention zur Vermeidung von Stack-Problemen zur Kenntnis genommen wird. Es gibt eine nette Tabelle hier, die einige Konventionen dokumentiert: https://msdn.microsoft.com/en-us/library/984x0h58.aspx –

+0

Können wir sagen, dass dies bestimmte illegale Optimierungen deaktivieren würde? – kesari

5

Es hat damit zu tun, wie die Funktion aufgerufen wird - im Prinzip die Reihenfolge, in der Dinge auf den Stapel gelegt werden und wer für die Bereinigung verantwortlich ist.

Hier ist die Dokumentation, aber es bedeutet nicht viel, wenn Sie den ersten Teil verstehen:
http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx

31

C oder C++ selbst tun, um diese Kennungen nicht definieren. Sie sind Compiler-Erweiterungen und stehen für bestimmte Aufrufkonventionen. Dies bestimmt, wo Argumente in welcher Reihenfolge platziert werden sollen, wo die aufgerufene Funktion die Absenderadresse findet und so weiter. Zum Beispiel bedeutet __fastcall, dass Argumente von Funktionen über Register übergeben werden.

Die Wikipedia Article bietet einen Überblick über die verschiedenen Aufrufkonventionen, die dort gefunden werden.

15

Die Antworten haben bisher die Details abgedeckt, aber wenn Sie nicht beabsichtigen, zur Assembly zu wechseln, müssen Sie nur wissen, dass sowohl der Anrufer als auch der Angerufene die gleiche Aufrufkonvention verwenden müssen. Ich bekomme Bugs, die schwer zu finden sind.

9

Ich stimme zu, dass alle Antworten soweit korrekt sind, aber hier ist der Grund. Die C- und C++ - Compiler von Microsoft bieten verschiedene Aufrufkonventionen für die (beabsichtigte) Geschwindigkeit von Funktionsaufrufen innerhalb der C- und C++ - Funktionen einer Anwendung. In jedem Fall müssen sich der Anrufer und der Angerufene darüber einigen, welche Aufrufkonvention verwendet werden soll. Jetzt stellt Windows selbst Funktionen (APIs) zur Verfügung, und diese wurden bereits kompiliert. Wenn Sie sie aufrufen, müssen Sie ihnen also entsprechen. Alle Aufrufe von Windows-APIs und Rückrufe von Windows-APIs müssen die __stdcall-Konvention verwenden.

+2

und es darf nicht mit _standard_call verwechselt werden, da es Standard-c ist! man könnte denken, dass wäre der Punkt von __stdcall, wenn man nicht besser weiß –

+2

Ein kleiner Nitpick: Es gibt ein paar Windows-APIs, die __cdecl anstelle von __stdcall verwenden - in der Regel diejenigen, die variable Anzahl von Parametern, wie wsprintf(). –

+0

Sie haben Recht. Es ist benannt nach einer CRT-Funktion, aber es ist eine API. Kannst du es zufällig von C# aufrufen? –

4

__stdcall wird verwendet, um die Funktionsargumente in den Stapel zu stellen. Nach dem Beenden der Funktion wird der Speicher automatisch freigegeben. Dies wird für feste Argumente verwendet.

void __stdcall fnname (int, int*) 
{ 
    ... 
} 

int main() 
{ 
    CreateThread (NULL, 0, fnname, int, int*......) 
} 

Hier ist der fnname hat args es direkt in den Stapel schieben.

1

Ich hatte nie diese bis heute vor verwenden. Weil ich in meinem Code Multi-Threading verwende und die Multi-Threading-API, die ich verwende, die Windows-Eins (_beginthreadex) ist.

den Faden zu starten:

_beginthreadex(NULL, 0, ExecuteCommand, currCommand, 0, 0); 

Die ExecuteCommand Funktion MUST das __stdcall Schlüsselwort in der Methodensignatur, um beginthreadex es zu nennen verwenden:

unsigned int __stdcall Scene::ExecuteCommand(void* command) 
{ 
    return system(static_cast<char*>(command)); 
}