2008-11-18 4 views
119

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

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

я был смущен относительно того, что этот идентификатор WINAPI был и нашел:

#define WINAPI  __stdcall 

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

+1

@AndrewProck "фиктивный" в этом случае изменение было в порядке, но в общем случае вы можете использовать ` ``, чтобы обойти глупый (и контрпродуктивный случай) 6 символов. – 2014-01-10 00:01:47

ответ

137

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

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

Википедия охватывает details.

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

+8

См. Этот вопрос для примера очень серьезных сбоев http://stackoverflow.com/questions/696306/run-time-check-failure-0-loading-queryfullprocessimagename-from-kernel32-dll – sharptooth 2009-04-17 04:08:14

+0

Если я не ошибаюсь, то эти вызывающие соглашения контролируют, как компилятор создает код сборки. При взаимодействии с ассемблерным кодом важно, чтобы вызывающее соглашение принималось к сведению, чтобы предотвратить проблемы со стеком. Здесь есть таблица с документами, в которой описаны некоторые соглашения: https://msdn.microsoft.com/en-us/library/984x0h58.aspx – 2015-07-24 17:03:37

5

Это связано с тем, как называется функция - в основном, порядок, в котором вещи помещаются в стек и кто несет ответственность за очистку.

Вот документация, но это ничего не значит, если вы не понимаете первую часть:
http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx

31

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

Wikipedia Article содержит обзор различных соглашений о вызовах, обнаруженных там.

15

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

9

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

4

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

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

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

Здесь fnname имеет арг она непосредственно толкают в стек.

1

Я никогда не имел не использовать это раньше до сегодняшнего дня. Потому что в моем коде я использую многопоточность, а API с несколькими потоками, который я использую, - это окна один (_beginthreadex).

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

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

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

unsigned int __stdcall Scene::ExecuteCommand(void* command) 
{ 
    return system(static_cast<char*>(command)); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^