Когда использовать соглашения о вызовах - PullRequest
6 голосов
/ 04 августа 2010

Каковы основные факторы использования различных соглашений о вызовах? Когда кто-то знает, как использовать определенные соглашения о вызовах, такие как __cdecl или __stdcall или __fastcall в разных случаях.

Примеры будут действительно оценены.

1 Ответ

13 голосов
/ 04 августа 2010

Большую часть времени вам не нужно беспокоиться об этом. Обычно вы будете использовать __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 равно #define 'd как __stdcall). Это необходимо, поскольку операционная система ожидает, что lpfnWndProc указывает на WNDPROC, , который использует соглашение CALLBACK .

Почти каждая функция Windows API, которая принимает обратный вызов, требует, чтобы функции обратного вызова использовали соглашение __stdcall, и, поскольку __cdecl обычно является значением по умолчанию, вы должны сделать это явным (вы должны использовать CALLBACK для оконных процедур ).

Это чрезвычайно важно, потому что повреждение стека может произойти, если операционная система пытается вызвать функцию не __stdcall. К сожалению, многие люди неправильно понимают, что Windows будет на самом деле проверять несоответствие соглашений о вызовах специально для оконных процедур .

Хотя __stdcall требуется для функций обратного вызова, передаваемых в функции WinAPI, функции, которые принимают переменное число аргументов, должны использовать соглашение о вызовах __cdecl, потому что только вызывающая сторона будет знать, как правильно извлечь переменное количество аргументов из стек. Поскольку __cdecl обычно используется по умолчанию, вам не нужно явно указывать __cdecl для функций, которые принимают переменное число аргументов.

Лично я не нашел использования для __fastcall, хотя я уверен, что кто-то нашел.

__clrcall имеет значение, только если вы взаимодействуете с управляемым кодом.

...