Dans CDECL, les arguments sont poussés sur la pile dans l'ordre inverse, l'appelant efface la pile et le résultat est renvoyé via le registre du processeur (plus tard, je l'appellerai "registre A"). Dans STDCALL, il y a une différence, l'appelant ne vide pas la pile, l'appelant le fait.
Vous demandez lequel est le plus rapide. Personne. Vous devez utiliser la convention d'appel native aussi longtemps que vous le pouvez. Modifiez la convention uniquement s'il n'y a pas de solution, lors de l'utilisation de bibliothèques externes qui nécessitent l'utilisation d'une certaine convention.
En outre, il existe d'autres conventions que le compilateur peut choisir par défaut, c'est-à-dire que le compilateur Visual C ++ utilise FASTCALL qui est théoriquement plus rapide en raison d'une utilisation plus étendue des registres du processeur.
Habituellement, vous devez donner une signature de convention d'appel appropriée aux fonctions de rappel passées à une bibliothèque externe, c'est-à-dire que le rappel qsort
de la bibliothèque C doit être CDECL (si le compilateur utilise par défaut une autre convention, nous devons marquer le rappel comme CDECL) ou divers rappels WinAPI doivent être STDCALL (tout WinAPI est STDCALL).
Un autre cas habituel peut être celui où vous stockez des pointeurs vers certaines fonctions externes, c'est-à-dire que pour créer un pointeur vers la fonction WinAPI, sa définition de type doit être marquée avec STDCALL.
Et ci-dessous est un exemple montrant comment le compilateur le fait:
/* 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)