우선 WINDEF.H를 보면 다음을 알 수 있다. CALLBACK = WINAPI = PASCAL = __stdcall WINAPIV = __cdecl 즉 window에서의 calling convention은 크게 __stdcall과 __cdecl로 생각할 수 있다.
그럼 __stdcall과 __cdecl의 공통점과 차이점을 살펴보자. 공통점은 함수의 인자를 스택에 쌓을 때 오른쪽에서부터 왼쪽으로 쌓기 때문에 가장 첫번째 인자가 스택의 맨 위로 올라온다. 차이점은 __stdcall은 호출된 함수, 즉 __stdcall로 정의된 함수 내부에서 스택이 청소되고 __cdecl은 호출한 함수에서 스택을 정리하여 준다. __cdecl의 이러한 특징 때문에 __cdecl로 정의된 함수는 가변 인자를 지원할 수 있게 된다. 왜냐하면 호출한 함수에서는 가변 인자의 스택의 크기를 알지만 호출된 함수에서는 가변 인자의 스택의 크기를 알 수 없기 때문이다.
그리고 흔히들 OS에서 사용되는 함수나 다른 프로그래밍 언어에서 사용할 수 있게 DLL로 만들 때 함수를 __stdcall로 선언해야 한다고 말한다. 왜 그럴까? 그것은 __stdcall이 서로 다른 프로그래밍언어 사이에서 통일된 표준이기 때문이다. OS는 특정 언어만을 지원할 수 없고 또한 서로 다른 프로그래밍 언어들이 서로 다른 함수의 인자 처리 방식을 사용한다면 한 프로그래밍 언어로 쓰여진 함수가 다른 프로그래밍 언어에서 사용되는 것이 불가능하다. 그래서 표준이 필요하였고 그것이 __stdcall인 것이다. 사실 이 부분은 내 주관적인 판단일 뿐이다.
또한 __stdcall이 __cdecl로 선언되는 것보다 프로그램의 크기가 작아지고 빠르다고 한다. 그 이유는 무엇일까? 이 부분은 데브피아에 '''고임''' 님이 어셈블리 코드까지 제시하면서 자세히 말씀해 주셨다. 아래는 고임님의 글에 본인이 약간의 수정을 가한 것이다.
여기서 보면 스택을 정리하는 코드가 빠져 있습니다. 따라서 스택 정리 코드가 없어진 stdcall 방식이 실행크기가 작아지고 속도도 명령어 하나 만큼이나 빨리지게 된 것입니다. 하지만 한가지 의구심이 듭니다. 어차피 호출당한 함수에서 해제를 하나 아니면 호출한 함수에서 해제를 하나 똑같이 해제를 하는데 호출당한 함수에서 해제를 하는 것이 속도나 크기가 더 줄어드는 것일까요? 엎어치나 되치나.. 스택을 어디선가 정리는 해야할텐데 도대체 ? 어떤 꽁수로? 이걸 해결했단말가? 여기에는 8086 아키텍쳐에 관련된 명령어가 그 원인으로 등장합니다. 그리고 스택을 정리한다는 것 자체가 그 함수를 호출한 뒤에 Add sp, 16으로 스택포인터를 인자의 크기만큼 변경을 시킨다는 이야기입니다. 근데 여기서 프로시저 즉 함수를 다 수행했을때 원래 상태로 돌아가게 될 때 쓰이는 명령어는 ret입니다. (프로시저와 함수라는 용어를 병행하고 있는데.. ㅡㅡ;; 그냥 하나의 분리된 코드 덩어리다 라고 이해해주시기 바랍니다. 정확히 보면 서로 의미가 틀리지만.. ㅡㅡ; ) 함수 시작하고, 함수가 끝났을때 ret 명령어로 호출한 부분으로 넘어가게 됩니다. 다시 말하면 이 명령어는 실행되던 함수를 바로 빠져나가게 됩니다. 따라서.. 스택을 정리할 시간이 전혀 없었습니다. 이에 8086설계자들은 함수에서 리턴이 될때 스택포인터(SP)를 적절한 위치로 리셋을 시킬 수 있는 ret명령어를 새로 제공을 하여 이 문제를 아주 손쉽게 해결해 버렸습니다. 즉 ret, n 이라는 명령어를 제공했다는 셈이지요.. 멋진 속담으로는 도랑치고 가재잡고 또는 멋진 고사성어로는 일석이조 라는 말로 표현된다 하겠습니다. 어차피 리턴할 걸 스택 포인터가 정리되는 부분으로 아예 리턴을 해버리란 이야기이지요.. 이것은 가만히 앉아서 프로그램의 속도와 크기를 이점을 살리는 일이었습니다. Add sp, 16 ;; -->> 추가된 코드.. 호출하는 부분에서 이렇게 코딩하는 대신 호출 받는부분에서 리턴할때 ret, 16으로 해결했다는 이야기지요.. 이래서 속도가 더빨라집니다. 크기도 줄어들구요.. 생각을 한번 해보자구요... 이런식의 함수가 굉장히 많이 호출된다면.. 크기나 실행 시간이 증가되는건 당연하겠지요..
마지막으로 정리를 하자면.. 첫째, stdcall 방식은 cdecl 방식보다 빠르지만 가변 인자를 지원하지 못한다. 둘째, OS가 호출하는 함수나 DLL에 들어가는 함수는 가능하면 stdcall을 쓴다.
첫댓글 봐도 잘 모르겠네여 ^^;;; stdcall이 좀 더 나아보이네여 ㅎㅎㅎ