● 맹글링

C++에서는 함수 중복을 하기 때문에 함수 이름이 같더라도 구별되는 인자열에 따라 다른 이름을 만들어 준다.

이를 함수 이름 맹글링(function name mangling)이라고 한다. 맹글링은 사전적 의미로 '토막토막 베다/알아듣지 못하게 만들다'라는 의미를 가진다.


맹글링의 실제 의미는 컴파일러가 어떤 일관된 규칙에 따라 함수를 부호화하는 것이다.


에러 메시지를 자세히 보면 VC++의 "


?swap@@YAXPAH0@Z"와 g++의 "swap_FPiT0"은 void swap( int*, int* ) 함수가 맹글링된 이름이다.


이 맹글링 방법은 컴파일러마다 다르지만 Ellis와 StrouStrup이 쓴 책 "The Annootated C++ Reference Manual"에  name encoding이라는 내용으로 소개되어 있다. 맹글리의 기본 원칙은 함수의 인자 타입, 지정자(modifier), 클래스의 멤버함수에 따라 부호를 할당한다.


int형은 i, double형은 d, char형은 c, float형은 f등으로, unsigned는 U, signed는 S, const는 C등으로 부호화한다.


또 포인터 타입은 P, 레퍼런스 타입은 R, 전역함수인 경우에는 F, 클래스 멤버함수인 경우에는 클래스 이름의 글자 개수에다 클래스 이름, 그리고 F를 연속해서 붙여준다. 클래스 이름과 같은 생성장와 소멸자는 함수 이름으로 ct, dt로 붙여준다.


예를 들어보자.

1    void f( int, const char * ) ;                         → f_FiPCcv

2    void f( unsigned, const String& ) ;             → f_FUiRC6Stringv

3    Complex::Complex( double, double ) ;      → _ct_7ComplexFdd

4    Complex::~Complex() ;                             → _dt_7ComplexFv

5    double Complex::csin() ;                           → csin_7ComplexFvd


이러한 원리로 C++에서는 컴파일을 할 때 함수 정의나 호출시 맹글링이 일어난다.

위의 첫 두 함수처럼 함수 이름은 'f'로 같지만 인자가 다르기 때문에 서로 다른 이름으로 맹글링된다.

따라서 함수 중복이 가능하며 타입 검사를 할 수 있는 것이다.

그렇지만 C에서는 함수 이름의 유일성이 보장되므로 맹글링이 일어나지 않고 단지 함수 이름 앞에 밑줄 문자(_)를 붙이는 것이 고작이다.


● extern "C"

그러면  C 함수에 대해 맹글링이 일어나지 않도록 하려면 어떻게 해야 하는가?


C++에서는 이를 타입 보장 링크(type-safe linkage)라는 메커니즘으로 제공한다. 에러를 고치려면 다음과 같이 고치도록 한다.


extern "C"

{

        #include "swap.h"

}


함수 하나에 대해서만 사용할 경우에는 extern "C" 문장 다음에 바로 함수 원형을 적어도 된다.

extern "C" int swap( int *, int * ) ;


함수 선언이 여러 개일 때는 중괄호로 감싸주어야 한다.


extern "C"

{

        int f() ;

        void g( int t ) ;

}


[extern "C"의 의미]

extern "C"문장은 맹글링을 하지 말라는 지시문이다.

그렇다면 C의 표준 라이브러리 함수, 예를 들어 printf()를 사용할 때도 extern "C"문장을 항상 적용해야 하는가?

만약, 함수 원형을 개별적으로 선언하고 사용하려면 적용해야 한다.


1    // printf.cpp

2    

3    extern "C" int printf( const char *... ) ;

4

5    void main()

6    {

7        printf( "야!" ) ;

8    }


반면 C 표준 헤더 파일 자체를 포함시킬 때는 적용하지 않아도 된다.

1    // printf.cpp

2

3    #include                  // c 표준 헤더 파일을 포함할 경우에는 extern "C" 지시어가 필요 없음

5    void main()

6    {

7        printf( "야!" ) ;

8    }


왜냐하면 stdio.h를 포함한 모든 표준 C 헤더 파일에는 다음과 같은 형태로 extern"C" 문장이 들어있기 때문이다.


#ifndef    __STDIO_H               // 조건부 컴파일:헤더 파일이 중복 포함되는 것을 방지

#define   __STDIO_H  


#ifdef    __cplusplus              // C++ 모드로 컴파일할 때

extern "C" {                            // 맹글링 방지

#endif

        ...                                     // C 함수 원형

int printf( cont char *, ...) ;      // C++모드로 컴파일할 때

        ...

#ifdef    __cplusplus

}

#endif

#endif        /* __STDIO_H */


__cplusplus는 예약된 매크로 상수로서 C++ 모드로 컴파일할 때 설정되어 extern "C" {} 문장을 수행하고,

C모드로 컴파일을 할 때는 매크로 상수를 정의하지 않기 때문에 extern "C" {} 문장을 수행하지 않는다.

따라서 C/C++ 두 언어로 모두 컴파일할 수 있다.


● type-safe linkage의 의미

 extern "C" 문장의 의미에 대해 한 가지 조심할 점은 C함수를 사용하더라도 C 컴파일러가 아닌 C++ 컴파일러가 해석하기 때문에 그 함수의 원형에 따라 타입 검사는 아주 정확히 한다는 것이다.

결코 C 프로그램에서 함수를 사용할 때처럼 타입 검사를 느슨하게 하지 않는다. 따라서 함수 원형을 정확하게 기술할 필요가 있다.

타 입 보장 링크(type-safe linkage)라는 말의 의미처럼 C++ 내에서 사용되는 C 함수는 컴파일 단계에서 C++ 함수와 동등하게 엄격한 타입 검사를 받는 것을 보장하고 링크 단계에서 이름을 알 수 있는 C 함수를 찾아 넣을 수 있다는 것이다. 이로써 유효한 타임을 갖는 C함수 호출이 가능해지는 것이다.


예 를 들어 두 행렬의 합을 구하는 함수 madd()를 C함수로 정의할 때, 임의의 행과 열을 갖는 행렬 연산을 위해 일차원 배열로 구현한다고 하자. 이 함수의 인자에 개념적으로 수학에서의 행렬과 논리적으로 개념이 동등한 이차원 배열을 실인자로 넘기는 경우, C에서는 에러를 내지 않지만 C++에서는 엄격한 타입 검사를 통해 타입 불일치 에러를 낸다.


따라서 extern "C" 지시어의 의미는 C++ 맹글링을 하지 않음으로써 C 함수를 사용할 수 있고 또 타입 검사는 C++ 규칙을 따르기 때문에 올바르지 못한 타입을 넘기는 것을 방지한다고 요약할 수 있다.


[extern "C"의 적용]

여기에서는 extern "C"를 함수에 국한해서 설명하였지만 사실 C 함수에만 적용되는 것이 아니다. C의 맹글링 규칙이 적용되는 심볼이 모두 해당된다



출처 : http://wen21.springnote.com/pages/2412238

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

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

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

,