먼저 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 뭐 이런식에 이름이였을것이다. 따라서 링크할때 찾을수 없어서 에러가 나는것이다.

그 역도 마찬가지

EOF

name mangling

친구넘한테 전화가 왔다. 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로 덤프뜨면 아래와 같다.

사용자 삽입 이미지

name mangling


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

+ Recent posts