__stdcall은 무엇입니까?


151

Win32 프로그래밍에 대해 배우고 있으며 WinMain프로토 타입은 다음과 같습니다.

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

WINAPI식별자가 무엇인지 발견하고 혼란 스러웠습니다 .

#define WINAPI      __stdcall

이것은 무엇을 하는가? 나는 이것이 리턴 타입 후에 무언가를 갖는 것에 혼란스러워합니다. 무엇입니까 __stdcall? 반환 유형과 함수 이름 사이에 무언가가있을 때 무엇을 의미합니까?


2
@AndrewProck이 경우 "더미 (dummy)"변경은 괜찮 았지만 일반적으로  s를 사용 하여 최소 6 자 이상의 어리석은 (그리고 반 생산적인 경우) 문제 를 해결할 수 있습니다 .
Adi Inbar 2018 년

답변:


170

__stdcall함수에 사용되는 호출 규칙입니다. 이는 컴파일러에게 스택 설정, 인수 푸시 및 반환 값 가져 오기에 적용되는 규칙을 알려줍니다.

다른 호출 규칙의 숫자가 있습니다, __cdecl, __thiscall, __fastcall그리고 멋지고 이름 __declspec(naked). __stdcallWin32 시스템 호출에 대한 표준 호출 규칙입니다.

Wikipedia에서 자세한 내용을 다룹니다 .

코드 외부에서 함수 (예 : OS API)를 호출하거나 OS에서 사용자를 호출 할 때 (WinMain에서와 같이) 주로 중요합니다. 컴파일러가 올바른 호출 규칙을 모르면 스택이 올바르게 관리되지 않으므로 매우 이상한 충돌이 발생할 수 있습니다.


8
매우 심각한 충돌의 예는 다음 질문을 참조하십시오. stackoverflow.com/questions/696306/…
sharptooth

내가 실수하지 않으면이 호출 규칙은 컴파일러가 어셈블리 코드를 생성하는 방법을 제어합니다. 어셈블리 코드와 인터페이스 할 때는 스택 문제를 방지하기 위해 호출 규칙을 고려해야합니다. 다음은 몇 가지 규칙을 설명하는 멋진 표입니다. msdn.microsoft.com/en-us/library/984x0h58.aspx
Nicholas Miller

이로 인해 특정 불법 최적화가 비활성화 될 수 있습니까?
kesari

40

C 또는 C ++ 자체는 이러한 식별자를 정의하지 않습니다. 그것들은 컴파일러 확장이며 특정 호출 규칙을 나타냅니다. 호출 된 함수가 리턴 주소를 찾는 위치 등을 순서대로 배치 할 위치를 결정합니다. 예를 들어 __fastcall은 함수의 인수가 레지스터를 통해 전달됨을 의미합니다.

위키 백과 기사 가 발견 다른 호출 규칙에 대한 개요를 제공합니다.


18

지금까지의 답변은 세부 사항을 다루었지만 어셈블리로 드롭하지 않으려면 발신자와 수신자 모두 동일한 호출 규칙을 사용해야한다는 것만 알면됩니다. 그렇지 않으면 버그가 발생합니다. 찾기가 어렵습니다.


12

지금까지의 모든 답변이 정확하지만 여기에 이유가 있습니다. Microsoft의 C 및 C ++ 컴파일러는 응용 프로그램의 C 및 C ++ 함수 내에서 의도 된 속도의 함수 호출에 대한 다양한 호출 규칙을 제공합니다. 각각의 경우, 발신자와 수신자는 어떤 통화 규칙을 사용해야하는지에 동의해야합니다. 이제 Windows 자체는 함수 (API)를 제공하며 이미 컴파일 된 기능이므로 호출 할 때이를 준수해야합니다. Windows API에 대한 모든 호출 및 Windows API의 콜백은 __stdcall 규칙을 사용해야합니다.


3
그리고 standard-c라는 점에서 _standard_call과 혼동해서는 안됩니다! 더 잘 모른다면 __stdcall의 요점이라고 생각할 수도 있습니다.
Johannes Schaub-litb

3
작은 nitpick : __stdcall 대신 __cdecl을 사용하는 Windows API가 몇 가지 있습니다. 일반적으로 wsprintf ()와 같이 가변 수의 매개 변수를 사용합니다.
Michael Burr

네가 옳아. 그것은 CRT 함수처럼 보이도록 명명되었지만 API입니다. 우연히 C #에서 P / Invoke하는 방법을 알고 있습니까?
Windows 프로그래머

이것을 테스트하지는 않았지만 pinvoke.net은 다음과 같은 서명을 제공합니다. "정적 extern int wsprintf ([Out] StringBuilder lpOut, string lpFmt, ...);"
Michael Burr

내 직감에 따르면 C # 컴파일러는 해당 규칙에 __cdecl 규칙을 사용하는 것을 알지 못합니다.
Windows 프로그래머



4

__stdcall은 함수 인수를 스택에 넣는 데 사용됩니다. 기능이 완료되면 자동으로 메모리 할당을 해제합니다. 고정 인수에 사용됩니다.

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

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

여기 fnname 에는 스택으로 직접 푸시되는 인수가 있습니다.


1

나는 오늘까지 이것을 사용하지 않았다. 내 코드에서 멀티 스레딩을 사용하고 있으며 사용중인 멀티 스레딩 API가 Windows (_beginthreadex)이기 때문입니다.

스레드를 시작하려면

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

ExecuteCommand를 기능은 반드시 beginthreadex가 전화를 위해서는 메소드 서명에서 __stdcall 키워드를 사용 :

unsigned int __stdcall Scene::ExecuteCommand(void* command)
{
    return system(static_cast<char*>(command));
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.