luce in altisBLUE SKY

category Photo

Blog


호출 규약

__fastcall은 C++빌더 프로그램을 하다보면 아주 많이 접하게 되는 키워드다.

__fastcall은 Calling Convention 콜링 컨벤션의 일종이다.

콜링 컨벤션은 함수를 부를때 어떻게 파라메터를 건네고 스택을 정리할지에 관해 어셈블리 수준에서의 처리를 규정하는 것으로, 곧 함수 호출규약 또는 호출규정이라고 한다.

호출규약의 핵심은 함수 파라메터를 스택에 왼쪽(앞)부터 넣을 것인가 오른쪽(마지막)부터 넣을 것이가 하는 것하고, 스택을 호출한 쪽에서 해제할 것인가 호출된 함수가 해제할 것인가 하는 것이다.  함수 리턴 값의 경우는 대부분 레지스터를 통해 건네지는데 주로 EAX 레지스터를 이용한다.

호출규약에는 다음과 같은 것들이 있다.

* __cdecl :

    전통적인 C 스타일의 호출규정으로 파라메터를 스택에 넣어 전달할 때 뒤에 것부터 먼저 넣고, 받을때는 레지스트를 통해 return 값을 받으며, 호출한 함수가 스택을 해제한다. 해제한다라는 표현외에 정리한다라는 표현을 쓰기도 하는데 스택에서 파라메터를 모두 버리는 작업을 뜻한다.

    C 시절에는 호출규약이 하나 뿐이었으므로 이 키워드가 필요없었다. 아니 콜링 컨벤션 키워드 자체가 없었다.
    C 형식의 함수가 필요할때는 반드시 붙여야 한다.

* __stdcall :

    OS가 윈도로  바뀌면서 대부분의 API 함수에 적용된 호출규약이다.  파라메터는 오른쪽부터 스택에 들어간다. 스택은 호출 받은 함수가 해제한다.

    그런데, 예외적으로 wsprintf 함수 같이 가변 파라메터를 쓰는 함수의 경우는 파스칼식 호출은 안되고, 전통적인 C 형식의 호출을 사용한다.


* __fastcall :

    전통적으로 파스칼에서 사용하던 호출규약을 좀 더 빠른 속도를 내도록 개선한 것이다. 일명 Register calling convention 레지스터 콜링 컨벤션이라고도 하는데, 처음 2개의 인자는 각각 ECX, EDX 레지스터에 담고 3번째 부터는 스택을 넣는데, 넣는 순서는 오른쪽의 것을 먼저 넣는다. 스택 해제는 호출 받은 함수 쪽에서 담당한다. 레지스터를 이용하므로 스택을 이용하는 경우보다 훨씬 코드도 짧고 속도도 빠르다.

    이름 그대로 가장 빠른 호출 속도를 가지고 있으나, 초고속 그래픽 등 극한의 스피드를 요구하는 프로그래밍 등 외에는 __fastcall로 얻을 수 있는 속도 이득은 극히 미미하다. 하지만 빈번히 호출되는 함수라면 속도 이득이 없다고 할수 없으며 잘 사용하면 최적의 속도를 내는 프로그래밍에 유리하다.

    참고적으로, Windows NT/200x 커널 모드 드라이버에서는 더 이상 레지스터를 이용한 호출규약을 사용하지 않는데, 이유는 레지스터는 CPU에 종속적이기 때문이다.

    왜 __fastcall이 많이 쓰이는가?

    그것은 가장 빠른 호출규약이기 때문이며, 델파이가 이 호출규약을 사용하는데 델파이로 제작된 VCL를 C++빌더도 같이 이용하기 때문에 __fastcall 을 많이 볼수 밖에 없다.

* 기타

    __declspec(naked)이라는 특이한 규약도 있고 __pascal, __fortran, __syscall로 잘 사용되지 않거나 사장된 호출규약도 있는데, 실무에서는 거의 볼일이 없다.



호출 규약에 대한 보다 깊은 이해를 위해서는 어셈블리어를 알아야 한다. 그러나 이상의 설명만으로도 고급 C++ 프로그래밍에 충분할 것이다.

그런데 필자가 예제로 보이는 클래스나 함수에서는 __fastcall 이 별로 없다. 왜일까? 이건 그냥 타이핑이 귀잖아서이다. 다른 아무런 이유가 없다. 물론 단축키를 써서 한번에 입력할 수 있지만 그것도 귀잖고해서, 꼭 필요한 경우만 사용했다.

그리고, VCL 프로그래밍을 위해 반드시 알아야 하는 것은, VCL 함수는 거의 __fastcall 규약을 사용하기 때문에 VCL 클래스를 상속할 때는 생성자 소멸자는 물론이고 상속하는 멤버 함수에는 __fastcall를 붙여 주어야 한다는 점이다. 자신이 새로 만드는 함수에는 호출규약을 자기 마음대로 결정할 수 있다.


질문 : 많이 보는 CALLBACK 이나 WINAPI 등의 호출규약의 실체는 뭔가?
답변 : 아래 코드를 참고하면 의문이 자동으로 풀릴 것이다.

//---- windef.h 헤더파일
#define CALLBACK    __stdcall
#define WINAPI      __stdcall
#define WINAPIV     __cdecl
#define APIENTRY    WINAPI
#define APIPRIVATE  __stdcall
#define PASCAL      __stdcall

'게임 > 프로그래밍' 카테고리의 다른 글

라이센스 이야기  (0) 2009.02.20
Scaleform  (0) 2009.01.07
Ganged Mode와 Unganged Mode  (0) 2008.11.21
포인터 선언 방법  (0) 2008.06.09
진공탄도 방정식  (0) 2008.05.08