'extern "C"'에 해당되는 글 1건

  1. 2008.12.10 extern "C"
Programming/C++2008. 12. 10. 16:14

C와 C++는 컴파일시 obj에 함수 이름, 변수 이름 등의 심벌을 기록하는 방식이 다르다.

그래서 C++ 컴파일러에서 C로 작성된 코드를 컴파일 하고자 할 때 사용한다.

 

C 컴파일러는 함수 이름을 그대로 사용하는 반면 C++ 컴파일러는 그대로 사용하지 않는다.
C++에서 프로그래머가 Func라는 이름으로 함수를 만들어도 이 이름과 동일한 함수를  만들 수 있다.

어떤 Func라는 함수는 정수를 인자로 받고 또 어떤 Func라는 함수는 실수를 인자로 받도록 만들 수 있다.

이렇게 이름이 동일한 여러 개의 함수가 나타날 수 있기 때문에 C++ 컴파일러는 내부적으로 Func라는 이름에다가 인자들의 타입 및 리턴 타입으로 어떤 문자들을 덧붙여서 각 함수들을 구분할 수 있도록 새로운 이름을 만든다.

extern "C"는 C++에서 C 함수를 사용하고자 할 때 컴파일러에게 C 함수라는 것을 알리는 역할을 한다.
이해를 돕기 위해 다음과 같은 프로그램을 예로 들어보자(파일 확장자는 .cpp로 만들어 C++ style로 컴파일한다).
add_1(), fadd_2(), add_3()이 컴파일 된 후 어떻게 이름이 바뀌는지 보면 왜 extern "C" 가 필요한지 알 수 있다.

#include "stdio.h"

int add_1(int a, int b);
float fadd_2(int a, int b);
extern "C" int add_3(int a, int b);

int main()
{
    int a = 2;
    int b = 3;
    int c;
    float fc;

    c  = add_1(a, b);
    fc = fadd_2(a, b);
    c = add_3(a, b);

    return 0;
}

/* -- 시험 삼아 여기를 막는다. --
int add_1(int a, int b)
{
    return a + b;
}

float fadd_2(int a, int b)
{
    return (float)(a + b);
}

int add_3(int a, int b)
{
    return a + b;
}
*/

################### compile/link 결과 ###############################
naver.obj : error LNK2001: unresolved external symbol _add_3
naver.obj : error LNK2001: unresolved external symbol "float __cdecl fadd_2(int, int)" (?fadd_2@@YAMHH@Z)
naver.obj : error LNK2001: unresolved external symbol "int __cdecl add_1(int, int)" (?add_1@@YAHHH@Z)

compile/link하면 위와 같이 link error가 발생한다.
자세히 보면
add_1 -> ?add_1@@YAHHH@Z
fadd_2 -> ?fadd_2@@YAMHH@Z
add_3 -> _add_3
와 같이 compile 과정에서 이름이 바뀐다.
add_1(), fadd_2()는 C++ style의 decorated name으로 바뀐 것이며, add_3()는 prototype에서 extern "C"를 주었으므로 C style로 '_'만 앞에 붙은 것이 차이점이다.

C++는 argument, return value에 따라 이름이 바뀌어 반드시 protype과 일치하는 function이 link된다. argument가 틀린 경우에는 같은 이름의 function이 여러 개 존재할 수 있으며 argument에 따라 적당한 function이 link된다.

C는 단순히 이름 앞에 '_' 만 추가되므로 argument가 틀리던 return value type이 틀리던 link는 될 수 있다. 심하게 잘못되면 compile/link는 되는데 오동작을 할 수도 있다.

C++는 컴파일시 함수 이름을 모두 다른 이름으로 바꿔주기 때문에 C에서 컴파일된 함수를 링크시킬 때는 해당 함수의 선언부 혹은 include 부분에 extern "C"라는 키워드를 사용하여 해당 함수가 C로 컴파일된 함수라는 것을 컴파일러에게 명시적으로 알려줘야 한다.

그런데 이 extern "C" 키워드는 C++에서 사용하는 것이므로 C에서는 사용되지 않는다. 따라서 반대로 C++의 함수를 C에서 사용하고자 한다면 C++ 소스를 컴파일 전에 소스 내에서 사용되는 함수의 선언을 모두
extern "C" 함수선언
이렇게 변환해 주어야 한다.

C에서는 이미 컴파일된 C++ 함수를 호출할 수 없다. 하지만, 만약 이렇게 C++ 소스에서 모든 함수를 extern "C"로 변환한다면 이 함수들은 C++의 함수 특성을 모두 잃게 된다. 즉, 클래스의 멤버 함수가 될 수 없고 인자만 틀리고 함수 이름은 같은 오버로딩 함수가 될 수도 없다.

보통 *.h 파일에 아래와 같이 하여 *.c, *.cpp에서 공용할 수 있는 protype 선언을 한다.

#if defined (__cplusplus)
extern "C" {
#endif

int func1();
int func2();
.
.
.

#if defined (__cplusplus)
};
#endif

참고,
extern "C" aaa();
extern "C" bbb();
는 아래와 같이 블록으로 잡아서 한번만 해주면 된다. 
 
extern "C"
{
    aaa();
    bbb();
}

Posted by skensita