pascall stdcall cdecl
데브피아 비주얼씨 강좌에서 고임이라는 분이 쓴글입니다.
자 이제 제가 이야기 할건.. 무엇이냐면.. 보시죠.
역사성을 좀 가미해서..
Borland c++ Version 3.1이 나온 당시에는
cdecl과 pascal 호출 규약만이 존재했습니다.
그 이후에 cdecl과 pascal의 장점만을 따온 _stdcall이 나오게 된거구요.
따라서 비슷하게 보이는데 서로 틀리게 보이는 건 ^^ 바로 이런 연유에서 비롯됩니다.
이 넘들에는 두 가지의 다른 점이 있습니다.(또 있으면 리플 달아주세요..)
(언더바는 생략할께요.. )
●인수를 스택에 집어넣는 방향에 따라서 다음과 같이 나뉘고
pascal : 인수를 스택에 저장하는 순서를 왼쪽에서 오른쪽으로 한다.
cdecl : 인수를 스택에 저장하는 순서를 오른쪽에서 왼쪽으로 한다.
stdcall : 인수를 스택에 저장하는 순서를 오른쪽에서 왼쪽으로 한다.
●스택에 인수를 pop 하는 주체에 따라서 다음과 같이 나뉩니다.
pascal : 호출을 당하는 쪽이 스택공간을 삭제합니다.
stdcall : 호출을 당하는 쪽이 스택공간을 삭제합니다.
cdecl : 호출을 하는 쪽이 스택공간을 삭제합니다.
이렇게 stdcall은 pascal방식과 cdecl방식을 혼합한 형태를 띄웁니다. (맞을 겁니다. 아마..)
(현제 VC에서 pascal방식은 지원하지 않습니다. )
stdcall은 두 가지의 장점을 모두 따왔다고 합니다. 들리는 소리엔 말이죠.. ㅡㅡ;
여기서 중요한 점은 아직도 콜백함수에서는 pascall이나 stdcall을 사용한다는 것이죠.
전 이것이 아주 궁금했습니다. 아직도 정확히 모르구요.. 누가 좀 정확히 가르쳐주셨으면
좋겠지만..
아무튼 왜 두 가지의 호출 규약을 동시에 다 써야만 했는지? 그 이유가 무척이나 궁금했습니다.
스택에 오른쪽부터 들어가던 아니면 왼쪽부터 들어가던 호출한넘이 스택공간을 삭제하던
호출 당한 넘이 스택공간을 삭제하던간에 왜 도대체 왜 pascal이라는 호출 규약을 사용하게 되었냐!
이거지요..
///// 자 이제부터 제가 실제적으로 할 이야기가 나옵니다. 집중 해주시구여. ㅡㅡ; //////
많은 분들은 MSDN에 나와있는 내용을 보았으므로 대충 cdecl과 stdcall이 어떻게 다른지를
알고 계실겁니다.
근데 도대체 왜 저렇게 나누게 되었을까요?
떠도는 말로는 다른 언어와 dll등등을 공유하기 위해서 사용되어진다! 라고 말씀을 하시기도 하고..
물론 일리는 있는 이야기입니다.
도대체 어떤말이 옳고 그른지도 정확히 판단이 안되는 것이 이 부분입니다.
제가 몇년간 아직도 그 이유를 찾지 못한.. 그러니까 확실한 동기도 모르고 stdcall이나 cdecl이니 하는
것들을 사용하고 있었다는 것이죠..
확실히 말씀드릴 수 있는 것들만 이야기 해보도록 하겠습니다.
● "cdecl과 pascal은 C와 C++의 포인터 때문에 생겨났다."
이 명제가 사실일까요? 사실은 아니더라도 왜 제가 이런 이야기를 하는지 들어보시기 바랍니다.
( 사실은 저도 잘 모릅니다. )
처음에 c와 C++의 디폴트가 cdecl방식으로 되어 있는 이유와 이것이 파스칼과 틀린 이유는 바로
충분히 cdecl이 더 프로그래머들한테는 호감이 갔습니다. 왜냐하면 가변인자를 지원하니까요..
가변 인자를 지원한다는 이야기는 바로 포인터를 써야 된다는 이야기인데 pascal에는 불행히도
존재 하지 않은 것이었지요..
물론 델파이에서 지원하기는 하지만 windows가 나올 당시에는 이런 포인터 개념은
C, C++밖에 존재 하지 않았습니다. 물론 어셈블리어에는 존재합니다 아주 에전에도 ㅡㅡ;;
( 혹시 다른것도 존재하나? 불안 초조.. )
MS는 윈도우즈의 API함수들을 만들때 많은 고심을 하다가 결국 다양한 언어로 윈도우즈 프로그램이
가능 하도록 pascal의 호출 규약을 따르게 되었을 겁니다.
그 이유는 비베를 확실히 밀고 있는 것으로 찾겠습니다.( 여기서부턴 경험론적 추측 ㅡㅡ;;)
그러면서도 불구하고 C와 C++의 최대의 장점인 가변인자를 버릴 수는 없어서 cdecl이라고 불리는
호출 규약을 만들어 놓고 C나 C++로 짠 프로그램 자체내에서 사용을 하도록 배려를 해주었다는 것이죠..
● 이제 주의 깊게 살펴볼 점은 우리는 MFC에서 __stdcall이라는 단어를 별로 쓰질 않습니다.
몇몇의 경우 빼고는 말이지요. 바로 콜백함수입니다.
윈도우 프로시저라고 불리는 코드 덩어리는 항상 pascal아니면 __stdcall이었습니다.
그리고 dll에서 사용되는 함수들이지요.. 이 함수들은 델파이에서도 사용될 수도 있고 VB에서도
사용이 될 수도 있는 가능성이 아주 농후한 놈이란걸 명심해 두십시요.
자 이제 살펴보기 전에..
자 그러면 몇가지를 정리 하고 넘어가도록 하지요.. 윈도우즈 OS 자체는 하나의 시스템이며, 위
의 말한 바와 같이 스택을 운용하는데 있어서 두 개의 다른 방식을 가질 수가 없습니다.
왜냐하면 시스템이 복잡해 지거덩여..
따라서 시스템 내부에서는 __stdcall방식으로 호출하고 있다는 것을 명심하시길 바라고 우리의
응용 프로그램안에서 스택을 어떻게 쓰던 전혀 상관 안하기때문에 우리는 전통적인 C, C++방식을 사용
할 수 있습니다.
자 대충 결론을 내어보면 다음과 같습니다.
API함수는 C, C++뿐만아니라 파스칼, VB같은 언어에서도 사용할 수 있게끔하기 위해서,
c나 C++의 방식을 포기하고 파스칼 방식을 따랐다. 그래서 __stdcall이된다.
DLL에 들어가는 함수들도 다른 언어에서도 사용이 될 수 있으므로, __stdcall로 호출규약을 맞추
어준다.
자 이제 콜백함수인데.. 콜백함수의 이름이 왜 콜백함수인지 부터 설명을 드리겠습니다.
여러분은 대부분 프로그램을 작성하실때 윈도우즈의 API함수를 불러다 썼을 겁니다. 맞습니까?
즉 다음과 같다는 것이지요.
OS(API) <---- 내 프로그램
이런 식으로 호출을 했습니다.
즉 내 프로그램에서 API의 함수를 불러다 썼지만..
콜백함수들은 내 프로그램에서 실행되는 것이 아니라. 위와 반대로
OS가 필요할때마다 부르는 함수가 바로 콜백 함수가 됩니다.
즉 OS를 기준으로 호출하는 순서가 반대로 되었다고 해서 CallBack함수가
된다는 것이지요.. 물론 WinMain도 마찬가지입니다.
자 그러면 __stdcall을 왜 붙이냐는 것이죠..
afx_msg라고 있는 함수나 WinMain이나 전부 OS가 호출을 하며,
이 OS는 사용하는 언어 자체의 기본(디폴트)이 __stdcall이기때문에
우리도 OS가 호출하는 함수들은 이 형식에 맞추어 주어야 한다는 슬픈 사실에
도달합니다.
한 나라에서 두 개의 언어를 쓰면 혼란이 오기때문에 표준어를 정하듯이,
이 넘의 윈도우즈라는 나라는 표준어가 __stdcall이고 사투리가 __cdecl이라는 것입니다.
어쨌든간에.. 저의 추리력 상상력 경험력 등등을 동원해서 대충 이야기를 끼워 맞추어보면
( 틀리면 리플 달아주십시요.. )
이렇습니다.
MSDN에는 이런 이야기는 나오지 않고 그저 그냥 설명만 해놓았지요..ㅡㅡ;
저는 어쨌든 그들의 필요성을 이렇게 억지로라도 만들지 않으면 영 찜찜해서 ㅡㅡ;;
자 그럼 수칙 제 한가지..
첫째, OS가 호출할 함수는 절대적으로 __stdcall을 쓴다.
왜냐하면 OS는 __stdcall의 형식으로 호출하기 때문이다.
둘째, DLL에 들어가는 함수를 만들때 왠만하면 __stdcall을 쓴다.
왜냐하면 다른 프로그램에서도 그 함수를 호출할 수 있기때문이다.
마지막 셋째, WinMain은 반드시.. _stdcall이다.
싫으면 에러만 날뿐이다.
고임
ps. 제 이야기는 틀릴 수도 있습니다.
확실하게 알고 계신분은 리플 달아주시길 바랍니다.
'Study > C++' 카테고리의 다른 글
메모리 관리 (0) | 2009.07.31 |
---|---|
호출규약 (0) | 2009.07.31 |
EC++ 2. define 대신 const, enum, inline 쓰기 (0) | 2009.07.29 |
How to Use __declspec(dllexport) in an MFC Extension DLL (0) | 2009.07.26 |
stl set (0) | 2009.07.23 |