Каковы ключевые факторы при использовании различных соглашений о вызовах? Когда делает кто-то знает для использования определенных соглашений о вызовах такой как __cdecl
или __stdcall
или __fastcall
в различных случаях.
Примеры были бы действительно apprciated.
В большинстве случаев вам не нужно беспокоиться об этом. Обычно вы будете использовать __ cdecl
, но только потому, что это значение по умолчанию в Visual C ++. Однако функции-члены C ++ по умолчанию используют соглашение __ thiscall
в Visual C ++
. (Довольно распространенная) ситуация, когда вам действительно нужно беспокоиться о соглашениях о вызовах, когда вы передаете обратные вызовы функциям API, например в Windows API:
// CALLBACK is #define'd as __stdcall
LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg
WPARAM wParam, LPARAM lParam);
// ...
windowClass.lpfnWndProc = &MyWndProc;
::RegisterClass(&windowClass);
Здесь мы объявляем MyWndProc ()
как имеющий соглашение __ stdcall
( CALLBACK
is #define
' d как __ stdcall
). Это необходимо, потому что операционная система ожидает, что lpfnWndProc
указывает на WNDPROC
, , который использует соглашение CALLBACK
.
Практически каждая функция Windows API, которая принимает обратный вызов, требует, чтобы функции обратного вызова использовали соглашение __ stdcall
, а поскольку __ cdecl
обычно используется по умолчанию, вы должны сделать это явным (вы будет использовать CALLBACK
для оконных процедур).
Это чрезвычайно важно, поскольку может произойти повреждение стека, если операционная система попытается вызвать функцию, отличную от __ stdcall
.К сожалению, достаточно много людей ошибаются в том, что Windows фактически проверяет несоответствие соглашения о вызовах специально для оконных процедур .
Хотя __ stdcall
требуется для функций обратного вызова, передаваемых функциям WinAPI, функции, которые принимают переменное количество аргументов, должны использовать соглашение о вызовах __ cdecl
, потому что только вызывающий будет знать, как правильно вытолкнуть переменное количество аргументов из стека. Поскольку по умолчанию обычно используется __ cdecl
, вам не нужно явно указывать __ cdecl
для функций, которые принимают переменное количество аргументов.
Я лично не нашел применения __ fastcall
, хотя уверен, что у кого-то есть.
__ clrcall
актуально, только если вы взаимодействуете с управляемым кодом.