본문 바로가기

UNIX_LINUX_C_C++

C에서 C++ 작성한 라이브러리를 사용하고자 한다면?

출처 : http://blog.naver.com/dreamakr?Redirect=Log&logNo=80003636883

친구넘한테 전화가 왔다. C에서 C++에서 작성한 라이브러리를 사용하고 싶다네.

C 나 C++ 소스가 컴파일 될때 우리가 선언한 함수들은 우리가 선언한 이름 그대로 남아 있지 않다.

컴파일러가 파라미터나 calling convention에 따라서 이름을 바꾸는데 이렇게 이름을 바꾸는 것을

name mangling 이라고 한다.

예를 들자면 c++같은 경우를 보면 함수 overriding이 가능하다.

즉 같은 이름으로 파라미터만 다르게 선언해서 사용할수 있다는 예기다. 그럼 컴파일러는 이 같은 이름에 놈들을 어떻게 구분하느냐 파라미터에 type을 가지고 그 함수 명을 변경해 버린다.

다른 함수들도 마찬가지다.

MSVC같은경우 .. 음 예전에 자료가 있었는데.. 찾으면 올리고.. 아님 말고..

예를 하나 들자면

void func_a( void ) ; 란 함수를 lib 로 만들어서 보면

"func_a@@YAXXZ"이런 식으로 변경되어 있을것을 볼수 있다.

더 자세히 보자

test.cpp

extern void func_a( void ) ;

extern "C" void func_b( void ) ;

void func_a( void )
{
return ;
}

void func_b( void )
{
return ;
}

두개의 함수를 똑같은 타입으로 선언했다. 차이점은 보는 봐야 같이 한넘은 extern "C" 를 이용했고 다른 한넘은 그렇지 않다는 차이 뿐이다.

그럼 이넘을 컴파일해서 라이브러리로 만들어서 hex로 덤프뜨면 아래와 같다.


보는 봐야 같이 이름이 많이 틀려진것을 볼 수 있다.
extern "C"를 하지 않은 func_a는 @@YAXXZ라고 붙어 있다. 이게 파라미터랑 콜링 컨벤션에 대한 정본데 정확한 내용은 기억 안남..
다른 한넘은 앞에 _(underscore)만붙는것을 볼수 있다.
처음으로 돌아가서 이처럼 C와 C++ 라이브러리는 혼용해서 사용할때는 name mangling을 고려해야 한다는것이다.

하여튼 이넘때문에 C에서 C++에서 작성한 라이브러리를 사용하고 싶을때는 C++ 라이브러리를 작성할때 애초에 C에서 사용될수 있다는것을 염두해 두고 작성해야 한다는 말이다.

즉 C에서 호출할수 있도록extern "C"를 선언하는 것이다.

역시 코드로 보자

C++ 라이브러리쪽

cpp.h

extern "C" void cpp_create( void ) ;

extern "C" void cpp_destroy( void ) ;

extern "C" void cpp_print(const char *) ;

cpp.c

class dummy {

void print( const char* msg ) {

printf( msg ) ;

}

} ;

static dummy* _theDummy = NULL ;

void cpp_create( void )

{

if( _theDummy == NULL )

{

_theDummy = new dummy ;

}

}

void cpp_destroy( void )

{

if( _theDummy )

{

delete _theDummy ;

}

}

void cpp_print( const char* msg )

{

if( _theDummy )

{

_theDummy->print( msg ) ;

}

}

cpp.h파일에서 보는 봐야 같이 C에서도 사용 되는 넘들은 extern "C"를 선언했다.

반대로

CPP에서 C에서 작성한 라이브러리 사용하려면 어떻게 할까?

여기서도 마찬가지로 모든 함수에 extern "C"를 무조건 선언하는 것이다.

즉 C에서 사용되던 C++에서 사용되던 같은 이름이 사용되도록 extern "C"를 붙여 둠으로써

어디서든 같은 이름으로 링크되는것을 보장해 준다.

먼소린지 모르겠다고? 흠..

즉C에서 작성한 라이브러리는 .h 파일과 .lib파일로 구성되어 있을것이다.

c.h

void c_func(void) ;

c.c

void c_func( void )

{

printf( "여기는 C") ;

}

이 라이브러리를 C언어를 사용하는 프로젝트에서 사용하는경우같은 환경임으로 아무 문제 없이 링크가 수행될테지만 만약C++소스에서 호출되는 경우link에러가 발생하게 된다.

즉어떤 CPP파일

call.cpp

#include "c.h"

void main(void )

{

c_func( ) ;

}

요런경우링크에러다.즉 CPP에서는 C에서와는 다른 name mangling을 수행함으로 c_func라는 함수 이름을 c_func@@XXYYZ 이런식으로 찾을꺼라는 말이다. 그럼 당연이 그런 이름에 함수가 없음으로에러가 발생한다.

즉이렇듯 c++에서도사용 가능하게 하려면 name mangling을 C 형태로 수행하도록 하면 되는것이다.

c.h

extern "C" void c_func( void ) ;

이것처럼 c 에서 작성하는 라이브러리에 함수는 무조건 extern "C" 를 지정하는 것이다.

이상..

방금 C에서 C++로 만든 lib에서 export한 함수를 호출해 봤더니 이런 에러가 나더군

Linking...
caller_namemangling.obj : error LNK2001: unresolved external symbol _func_a
Debug/caller_namemangling.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

즉 c쪽에서는 func_a() 라는 함수를 호출했지만 이넘이 C++쪽에서 만들어진 넘이라

이름이 좀 다르다 앞에서 설명했던것처럼 func_a@@XXYYZ 뭐 이런식에 이름이였을것이다. 따라서 링크할때 찾을수 없어서 에러가 나는것이다.

그 역도 마찬가지

'UNIX_LINUX_C_C++' 카테고리의 다른 글

좋은 정보가 많은 블러그 목록  (0) 2011.10.16
Linux 에서 pthread를 최대 생성가능한 thread 수를 측정  (0) 2011.10.16
bind error 방지 하기  (0) 2011.10.16
Poll_thread 소켓  (0) 2011.10.16
extern의 사용  (0) 2011.10.16