В случае, когда аргументы CDECL помещаются в стек в обратном порядке, вызывающая сторона очищает стек и результат возвращается через реестр процессора (позже я назову его «регистр A»).В STDCALL есть одно отличие: вызывающий не очищает стек, а вызывающий -. 1001
Вы спрашиваете, какой из них быстрее.Ни один. Никто.Вы должны использовать соглашение о вызовах как можно дольше.Измените соглашение, только если нет выхода, когда используются внешние библиотеки, требующие использования определенного соглашения.
Кроме того, существуют другие соглашения, которые компилятор может выбрать в качестве одного по умолчанию, т.е. компилятор Visual C ++ использует FASTCALL, который теоретическибыстрее из-за более широкого использования регистров процессора.
Обычно вы должны дать правильную сигнатуру соглашения о вызовах для функций обратного вызова, передаваемых в какую-либо внешнюю библиотеку, т. е. обратный вызов qsort
из библиотеки C должен быть CDECL (если компиляторпо умолчанию используется другое соглашение, тогда мы должны пометить обратный вызов как CDECL) или различные обратные вызовы WinAPI должны быть STDCALL (весь WinAPI является STDCALL).
Другой обычный случай может быть, когда вы храните указатели на некоторые внешние функции, то есть для созданияуказатель на функцию WinAPI, определение ее типа должно быть помечено STDCALL.
А ниже приведен пример, показывающий, как это делает компилятор:
/* 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)