Wenn CDECL-Argumente in umgekehrter Reihenfolge auf den Stapel geschoben werden, löscht der Aufrufer den Stapel und das Ergebnis wird über die Prozessorregistrierung zurückgegeben (später werde ich es "Register A" nennen). In STDCALL gibt es einen Unterschied: Der Aufrufer löscht den Stapel nicht, die Calle nicht.
Sie fragen, welches schneller ist. Niemand. Sie sollten die native Anrufkonvention so lange wie möglich verwenden. Ändern Sie die Konvention nur, wenn es keinen Ausweg gibt, wenn Sie externe Bibliotheken verwenden, für die bestimmte Konventionen verwendet werden müssen.
Außerdem gibt es andere Konventionen, die der Compiler als Standard auswählen kann, dh der Visual C ++ - Compiler verwendet FASTCALL, was theoretisch schneller ist, da Prozessorregister umfangreicher verwendet werden.
Normalerweise müssen Sie Rückruffunktionen, die an eine externe Bibliothek übergeben werden, eine ordnungsgemäße Signatur der Aufrufkonvention geben, dh der Rückruf qsort
von der C-Bibliothek muss CDECL sein (wenn der Compiler standardmäßig eine andere Konvention verwendet, müssen wir den Rückruf als CDECL markieren) oder verschiedene WinAPI-Rückrufe müssen STDCALL (ganze WinAPI ist STDCALL).
Ein anderer üblicher Fall kann sein, wenn Sie Zeiger auf einige externe Funktionen speichern, dh um einen Zeiger auf die WinAPI-Funktion zu erstellen, muss deren Typdefinition mit STDCALL markiert sein.
Das folgende Beispiel zeigt, wie der Compiler dies tut:
/* 1. calling function in C++ */
i = Function(x, y, z);
/* 2. function body in C++ */
int Function(int a, int b, int c) { return a + b + c; }
CDECL:
/* 1. calling CDECL 'Function' in pseudo-assembler (similar to what the compiler outputs) */
push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x'
call (jump to function body, after function is finished it will jump back here, the address where to jump back is in registers)
move contents of register A to 'i' variable
pop all from the stack that we have pushed (copy of x, y and z)
/* 2. CDECL 'Function' body in pseudo-assembler */
/* Now copies of 'a', 'b' and 'c' variables are pushed onto the stack */
copy 'a' (from stack) to register A
copy 'b' (from stack) to register B
add A and B, store result in A
copy 'c' (from stack) to register B
add A and B, store result in A
jump back to caller code (a, b and c still on the stack, the result is in register A)
STDCALL:
/* 1. calling STDCALL in pseudo-assembler (similar to what the compiler outputs) */
push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x'
call
move contents of register A to 'i' variable
/* 2. STDCALL 'Function' body in pseaudo-assembler */
pop 'a' from stack to register A
pop 'b' from stack to register B
add A and B, store result in A
pop 'c' from stack to register B
add A and B, store result in A
jump back to caller code (a, b and c are no more on the stack, result in register A)