C뿐만 아니라 모든 프로그래밍 언어는 목적 파일(obj)을 만들고 링크에 의해 목적 파일을 연결함으로써 최종 실행 파일을 만든다. 이때 목적 파일로 자신이 정의한 함수의 명칭과 주소를 공개하도록 되어 있고 이 명칭 공개 방식이 언어에 상관없는 표준 포맷으로 규정되어 있다. 그래서 C와 파스칼처럼 각각 다른 언어로 컴파일된 오브젝트 파일들이 링크될 수 있는 것이다.

초기의 C++도 마찬가지로 이런 범용 링커(linker)를 사용하도록 디자인되었다. 그런데 범용 링커는 함수를 오로지 이름으로만 찾기 때문에 C++의 오버로딩된 함수들을 제대로 구분하지 못한다. 그래서 C++은 함수의 이름을 외부로 공개할 때 인수의 개수와 타입에 대한 정보까지 함수명에 포함시키는데 이런 명칭을 작성하는 것을 이름 장식(name mangling)이라고 한다. 그래서 C++로 컴파일한 목적 파일의 함수명을 보면 함수 이름외에도 앞뒤로 이상한 기호들이 붙어 있다. 앞에서 만든 Overload.cpp의 목적 파일에는 세 개의 Add함수의 이름이 다음과 같이 작성된다.


?Add@@YANNN@Z

?Add@@YAHHHH@Z

?Add@@YAHHH@Z


Add라는 함수 이름 외에도 뒤쪽에 인수의 개수나 타입에 대한 정보들이 부호화되어 표기되어 있다. 오버로딩된 함수들의 외부 명칭이 이렇게 작성되므로 링크 단계에서는 각 함수들이 다른 함수처럼 인식되는 것이다. 그런데 모든 언어가 오버로딩을 지원하지 않기 때문에 C++의 이런 기능이 다른 언어와 혼합 프로그래밍을 할 때는 문제가 될 수 있다. 그래서 다른 언어와 링크되어야 하는 모듈은 이런 이름을 작성하지 말고 함수의 명칭을 이름만으로 외부로 공개할 필요가 있다.

이때 사용하는 지시자가 바로 extern "C"이다. 함수앞에 이 지시자를 사용하면 오버로딩 기능은 사용할 수 없지만 다른 언어와 링크될 수 있는 범용 함수를 만들 수 있다. 이렇게 만들어진 함수는 C에서도 호출 가능하다. 지금 당장 여러분들이 이 지시자를 사용할 일은 없겠지만 차후에 윈도우즈 환경에서 DLL을 만들거나 할 때는 이 지시자가 필요할 것이다. 윈도우즈의 DLL 포맷은 이름으로 함수를 찾기 때문에 오버로딩을 지원하지 않는다.

extern "C" 지시자는 C++이 C나 다른 언어를 위해 이름 장식을 하지 않도록 할 때 사용하기도 하지만 반대의 경우에도 이 지시자가 필요하다. 즉, 이미 C로 만들어진 함수를 C++에서 호출하고자 할 때 이 함수의 원형 앞에 extern "C"가 있어야 한다. 그렇지 않으면 링커가 장식된 이름으로 함수를 찾게 되므로 C의 함수를 제대로 연결하지 못한다. C++로만 함수를 작성한다면 굳이 이 지시자를 사용할 필요가 없다.


WINAPI의 의미(__stdcall)
 
function calling에 있어서 convention이 여럿 있게 마련인데요.

그런 게 있는 이유는 언어별로 다 틀리기 때문이죠.

따라서 님이 만약 어떤 dll을 만들어서 이런 저런 s/w에서 쓸 수 있게 하려면,
basic용, c++용, pascal용 등등을 따로 만들어야겠죠?

그렇게 되면 시간 및 비용이 많이 들게 됩니다.

그리고 dll의 본래 취지에서 벗어나게 되죠.

그래서 WINAPI라게 선언을 하는 거죠.

WINAPI를 찾아보시면..

#define WINAPI __stdcall

라고 되어 있는데요..

__stdcall 이라는 keyword로 선언된 함수는 함수가 return되기 전에 stack을 정리하게 됩니다.

좋은 비교 대상으로 __cdecl이라는 keyword가 있는데요..

__cdecl 이라는 keyword로 선언된 함수는 함수가 return된 후에 stack을 정리하게 됩니다. ( c/c++ )

따라서 __cdecl keyword를 사용하게 되면 stack을 정리하는 code가 필요하게 되죠.

이런 이유로, CALLBACK macro나 PASCAL macro도 찾아보면 __stdcall 이죠.
( 문자 그대로 standard calling 입니다. )


이외에도 차이점은 있을 거라고 생각됩니다만, 어쨌거나 님께서 질문하신 WINAPI,
즉 __stdcall의 용도는 서로 다른 compiler로 제작된 binary에 공통된 interface를
( - 정확히는 pascal 형식으로 알고 있습니다.. ) 제공하기 위한 것에 목적이 있다고 보시면 됩니다...

참고가 되셨길..


- 네이버에서 greathjm 님의 글을 발췌했습니다.


main.cpp 와 hello.c 그리고 hello.h 로 이루어진 화일이 있다. hello.c 에는 void 형의 hello() 란 함수가 정의되어 있고, hello.h 에는 hello() 함수의 원형이 선언되어 있다.
main.cpp 함수에서 이 hello 함수를 사용하길 원한다면, 언뜻 아래와 같은 방법으로 컴파일 하려고 시도할 것이다.

gcc -c hello.o
g++ -o hello main.cpp hellow.o

그러나 이를 컴파일 해보면 아래와 같은 에러가 발생한다.

/tmp/ccr6TqS7.o: In function `main':
/tmp/ccr6TqS7.o(.text+0x7): undefined reference to `hello(void)'

이런 일이 발생하는 이유는 C와 C++의 각 컴파일러가 알고 있는 함수 이름이 서로 틀릴수 있다는 데에서 발생한다. C++ 에서는 같은 함수이름이 overloading 를 통해서 여러개 존재할수 있지만 C에서는 오직 하나만 존재할수 있음으로, 실지 사용할 함수명을 리턴값과 인자값 까지 명시 해서 컴파일러에게 정확하게 알려줄 필요가 있다.
이럴경우 extern "C" {함수} 를 사용하면 된다.

extern "C" { void hello(); }

예제 코드
main.cpp
extern "C" { void hello(); }
int main()
{
hello();
}
hello.c
#include "hello.h"
#include <stdio.h>

void hello()
{
printf("hello world!!");

출처 : joinc
}

'Linux > Programming in UNIX env.' 카테고리의 다른 글

multi-core에서 spinlock 없이 프로그래밍 하기  (0) 2010.07.17
name mangling  (0) 2010.05.18
Linux Kernel Linked List Explained  (0) 2010.03.01
alarm 과 sleep 그리고 usleep  (0) 2009.08.24

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,