Я работаю над существующим проектом C ++ с Visual Studio, и я обнаружил, что почти каждое объявление функции получает __cdecl
перед именем функции, например:void __cdecl functionName()
, Затем я перехожу к определению __cdecl
, который находится в winnt.h
файл:
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define NTAPI __stdcall
#else
#define _cdecl
#define __cdecl
#define NTAPI
#endif
Я искал Cdecl и получил, что это соглашение о вызовах по умолчанию для программ на C и C ++, но код выше говорит мне, что __cdecl
не распространяется ни на что. Так зачем ставить __cdecl
перед именем функции, так как это просто ничего? или я неправильно понял код выше?
в чем смысл #define __cdecl »
Линии, начинающиеся с #
являются директивами препроцессора. #define
директива, которая определяет макрос препроцессора. #define __cdecl
определяет макрос с идентификатором __cdecl
и пустая замена. Если такой макрос определен, процессор заменит все экземпляры __cdecl
с пустой строкой.
Так зачем помещать __cdecl перед именем функции, поскольку это просто ничего?
Взгляните на директивы в начале рассматриваемого определения:
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) #else
Макрос определен условно. Когда макрос не определен, __cdecl
не расширится ни к чему. Когда не расширены до нуля, __cdecl
это специфический для Microsoft спецификатор функции, как вы обнаружили.
Условно определенный макрос позволяет писать код, который использует __cdecl
в системах, которые позволяют это, и автоматически удаляют это в системах, которые этого не делают.
Но я все еще путаюсь с #if (_MSC_VER> = 800) || определенная (_STDCALL_SUPPORTED) строка, что это значит?
Это директива препроцессора, которая проверяет, является ли макрос _MSC_VER
имеет большее значение, чем 800, или, если макрос _STDCALL_SUPPORTED
определено. Если тест ложен, то код между #if и #else удаляется. Если это правда, то код между #else и #endif удаляется.
Это означает, что если API определен как использующий NTAPI, он сгенерирует код, который использует соглашение о вызовах __stdcall — разновидность соглашения о вызовах Pascal, в котором вызываемый объект очищает стек. С __cdecl вызывающая сторона очищает стек (поэтому он поддерживает функции с переменным типом).
И все это зависит от #if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)