Соглашение о вызове функции должно соблюдаться вызывающей стороной. Если он есть, то должен быть какой-то вызывающий объект этой функции, который будет предполагать, что он должен быть вызван определенным образом. Это обычно важно, когда у вас есть функция обратного вызова.
Кроме этого, stdcall
предназначен для уменьшения размера кода по сравнению с cdecl
путем перемещения кода очистки аргумента от вызывающего к вызываемому (который может использоватьret imm16
на x86).
Это старая микрооптимизация для архитектуры IA-32. MSVC принимает ключевое слово __stdcall
и на других архитектурах, но ничего не делает там .
Проверьте этот пример:
__declspec(noinline) int sum(int a, int b)
{
return a + b;
}
int add1(int a)
{
return sum(a, 1);
}
MSVC компилирует это в:
int sum(int,int) PROC
mov eax, DWORD PTR _a$[esp-4]
add eax, DWORD PTR _b$[esp-4]
ret 0 ; this instruction will be replaced
int sum(int,int) ENDP
int add1(int) PROC
push 1
push DWORD PTR _a$[esp]
call int sum(int,int)
add esp, 8 ; this instruction will be removed
ret 0
int add1(int) ENDP
И версия с stdcall
:
__declspec(noinline) int __stdcall sum(int a, int b)
{
return a + b;
}
int add1(int a)
{
return sum(a, 1);
}
, которая компилируется в:
int sum(int,int) PROC
mov eax, DWORD PTR _a$[esp-4]
add eax, DWORD PTR _b$[esp-4]
ret 8 ; 0 argument replaced with 8
int sum(int,int) ENDP
int add1(int) PROC
push 1
push DWORD PTR _a$[esp]
call int sum(int,int)
ret 0 ; extra instruction is missing here
int add1(int) ENDP
Обратите внимание, как во 2-м примере используется ret 8
и вызывающая сторонане имеет дополнительных add esp, 8
.