Вопрос

Я изучаю программирование на Win32, а прототип WinMain выглядит следующим образом:

int WINAPI WinMain ( HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show )

Я был озадачен тем, для чего этот идентификатор WINAPI и был найден:

#define WINAPI      __stdcall

Что это делает? Я смущен тем, что что-то вообще есть после типа возврата. Для чего нужен __stdcall ? Что это значит, если между типом возвращаемого значения и именем функции есть нечто?

Это было полезно?

Решение

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

Существует ряд других соглашений о вызовах, __cdecl , __ thiscall , __ fastcall и чудесно названных __naked , __stdcall - это стандартное соглашение о вызовах для системных вызовов Win32.

Википедия охватывает подробности .

Это в первую очередь имеет значение, когда вы вызываете функцию вне вашего кода (например, API-интерфейс ОС) или ОС вызывает вас (как в случае с WinMain). Если компилятор не знает правильного соглашения о вызовах, вы, вероятно, получите очень странные сбои, так как стек не будет управляться правильно.

Другие советы

Сам C или C ++ не определяют эти идентификаторы. Они являются расширениями компилятора и обозначают определенные соглашения о вызовах. Это определяет, куда поместить аргументы, в каком порядке, где вызываемая функция найдет адрес возврата и так далее. Например, __fastcall означает, что аргументы функций передаются через регистры.

Статья в Википедии содержит обзор различных соглашений о вызовах, найденных там.

Ответы до сих пор охватывали детали, но если вы не собираетесь переходить к сборке, то все, что вам нужно знать, это то, что и вызывающий, и вызываемый должны использовать одно и то же соглашение о вызовах, в противном случае вы получить ошибки, которые трудно найти.

Я согласен, что все ответы пока верны, но вот причина. Компиляторы Microsoft C и C ++ предоставляют различные соглашения о вызовах для (предполагаемой) скорости вызовов функций в функциях C и C ++ приложения. В каждом случае вызывающий абонент и вызываемый абонент должны договориться о том, какое соглашение о вызовах использовать. Теперь сама Windows предоставляет функции (API), и они уже скомпилированы, поэтому, когда вы вызываете их, вы должны соответствовать им. Любые вызовы API-интерфейсов Windows и обратные вызовы из API-интерфейсов Windows должны использовать соглашение __stdcall.

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

void __stdcall fnname ( int, int* )
{
    ...
}

int main()
{
    CreateThread ( NULL, 0, fnname, int, int*...... )
}

Здесь у fnname есть аргументы, которые он непосредственно помещает в стек.

Мне никогда не приходилось использовать это раньше, до сегодняшнего дня. Это потому, что в моем коде я использую многопоточность, а многопоточность API, которую я использую, является windows (_beginthreadex).

Чтобы начать тему:

_beginthreadex(NULL, 0, ExecuteCommand, currCommand, 0, 0);

Функция ExecuteCommand ДОЛЖНА использовать ключевое слово __stdcall в сигнатуре метода, чтобы ее мог вызвать beginthreadex:

unsigned int __stdcall Scene::ExecuteCommand(void* command)
{
    return system(static_cast<char*>(command));
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top