У CDECL аргументи висуваються в стек у порядку зворотного виклику, абонент очищає стек, а результат повертається через реєстр процесора (пізніше я називатиму це "реєстром А"). У STDCALL є одна відмінність: абонент не очищає стек, а той, хто викликає.
Ви запитуєте, який з них швидший. Ніхто. Ви повинні користуватися умовами рідних дзвінків, поки можете. Змінюйте конвенцію, лише якщо немає виходу, при використанні зовнішніх бібліотек, що вимагають використання певної конвенції.
Крім того, існують інші домовленості, які компілятор може вибрати за замовчуванням, тобто компілятор Visual C ++ використовує FASTCALL, що теоретично швидше завдяки більш широкому використанню регістрів процесора.
Зазвичай ви повинні надати належний підпис qsort
дозволу виклику для функцій зворотного виклику, переданих до якоїсь зовнішньої бібліотеки, тобто зворотний виклик до бібліотеки C повинен бути CDECL (якщо компілятор за замовчуванням використовує інше узгодження, тоді ми повинні позначити зворотний виклик як CDECL) або різні зворотні виклики WinAPI повинні бути STDCALL (весь WinAPI - це STDCALL).
Інший звичайний випадок може бути, коли ви зберігаєте вказівники на деякі зовнішні функції, тобто для створення вказівника на функцію WinAPI його визначення типу має бути позначене STDCALL.
А нижче - приклад, що показує, як це робить компілятор:
i = Function(x, y, z);
int Function(int a, int b, int c) { return a + b + c; }
CDECL:
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)
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:
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
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)