함수 호출시 매개변수를 전달하는 방식과 스택 프레임을 반환하는 방식을 약속해 놓은것을 가리켜 함수 호출규약이라고 부른다

 
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define APIENTRY __stdcall
 
int __stdcall STDCallFunction(int a, int b);
int APIENTRY wWinMain(//);
  • Windows 시스템 함수 선언에서는 매크로를 사용하여 __stdcall을 표현한다.
  • 함수 호출규약을 명시하지 않은 함수들은 디폴트 선언을 따르게 된다.(그동안 계속 사용하던 방식)

__cdecl

  • C/C++의 디폴트 호출규약
  • 오른쪽에 있는 매개변수가 먼저 스택에 쌓이는 C스타일 방식
  • Caller가 스택 프레임을 정리
//Caller(main함수)에서 스택 정리
 
int Func(int a, int b)
{
	return a+b;
}
 
int main()
{
	Func(1,2);
	return 0;
}

**호출 순서1

  1. 매개 변수를 스택에 저장(2, 1 순서)
  2. Func 함수를 호출(이동)
  3. Func에서 [스택 포인터]를 이용하여 스택에 저장된 데이터 사용
  4. return 이후 main함수로 복귀
  5. main함수에서 SP를 Func 호출로 줄어든 만큼 다시 증가(스택 프레임 정리)

__stdcall

  • 호출된 함수 내에서 스택 프레임을 반환
  • Win32API에서 사용하는 CallBack 함수에서 자주 사용됨
//Callee(Func함수)에서 스택 정리
 
int Func(int a, int b)
{
	return a+b;
}
 
int main()
{
	Func(1,2);
	return 0;
}

**호출 순서

  1. cdecl과 동일
  2. return 부분에서 SP정리 시 Func에서 정리

__fastcall

  • cdecl과 매우 유사하지만 전달할 매개 변수의 개수에 따라 스택의 사용 여부 결정
  • 매개 변수가 2개 이하일 경우 ECX, EDX 라는 레지스터에 저장하는 방식으로 인자를 전달(접근, 연산속도 up)2
  • 매개 변수가 2개를 넘을 경우 cdcel 방식과 마찬가지로 3번째 매개 변수 부터 스택을 사용

cdecl과 stdcall

  • 어셈블리 수준에서 두 방식을 비교했을 때 stdcall은 코드 한줄로 return과 스택 정리가 가능 하지만, cdecl 방식은 return 후 스택을 정리하는 코드가 더 필요하다3
  • printf 같은 가변인자 함수는 Caller가 스택을 정리하는 cdecl방식을 사용해야만 한다4

Footnotes

  1. 매개변수 뿐 아니라 돌아올 주소 값, 사용 중인 지역 변수도 있지만 생략

  2. 레지스터는 CPU와 바로 붙어있기 때문에 접근이 매우 빠르다

  3. 단순히 한줄이지만 CPU 명령 하나를 줄이는 것이기 때문에 상당한 성능차이가 있다

  4. 몇 개의 인자가 사용 될지 Caller만 알 수 있기 때문