Post

C++에서 C로 컴파일된 함수를 사용하기


C++ 함수와 C 함수가 다른 이유


C++에서는 C와 다르게 함수 오버로딩이라는 기능을 제공해 준다.
이러한 기능이 가능한 이유는 C++ 컴파일러가 함수를 컴파일할 때 함수의 이름을 새롭게 만들어 주기 때문이다.
컴파일러가 새롭게 이름을 만들어주는 이 기법을 Name mangling이라고 부른다.

아래 소스코드를 g++로 컴파일하고 nm으로 살펴보면 쉽게 이해할 수 있다.

1
2
3
4
5
6
7
8
9
int cppfunction1(int a)
{
    return a;
}

int cppfunction1()
{
    return -1;
}
1
2
g++ -c cppfunc.cpp
nm cppfunc.o
1
2
0000000000000000 T _Z12cppfunction1i
0000000000000010 T _Z12cppfunction1v

함수의 이름 뒤에 인자가 어떤 타입인지 추가된 것을 알 수 있다.
사람이 보기에는 같은 이름의 함수이지만 컴파일러 입장에서는 다른 함수로 만든 것이다.
이런 원리로 함수 이름과 인자 타입의 조합으로 호출해야 하는 함수를 컴파일러 찾을 수 있다.

이번에는 C에서 함수 이름이 어떻게 만들어지는지 아래 소스코드를 gcc로 컴파일하고 nm으로 살펴보자.

1
2
3
4
int cfunction1(int a)
{
    return a;
}
1
2
gcc -c cfunc.c
nm cfunc.o
1
0000000000000000 T cfunction1

입력했던 이름 그대로 컴파일이 된 것을 알 수 있다.
C++과 다르게 인자 타입의 정보 없이 함수 이름만 있으므로 함수 오버로딩 기능을 제공할 수 없다.
또한 이대로라면 .cpp 파일에서는 .c 파일에서 정의한 함수를 사용할 수 없다.
이름을 만드는 규칙이 다르기 때문에 함수를 찾을 방법이 없는 것이다.


이름을 만드는 규칙을 통일시킬 수 있는 여러 가지 방법


사실, 문제를 해결하는 방법은 여러 가지가 있다.

  • 파일의 확장자를 변경하여 모든 파일을 .cpp 혹은 .c 로 통일한다.
  • g++로 모두 컴파일 한다.

두 번째 방법에 대해서 추가로 설명하자면, .c 파일을 g++로 컴파일하면 Name mangling기법이 적용된다.

1
2
g++ -c cfunc.c
nm cfunc.o
1
0000000000000000 T _Z10cfunction1i

하지만 위 두 가지 방법 모두 컴파일할 수 있는 소스코드가 있어야 한다는 제약조건이 있다.


현실적인 해결 방법 - extern “C”


실제로 우리가 마주하게 되는 상황은 그리 간단하지 않다.
사용하고 싶은 함수는 이미 .c 파일에 정의되어 있었고 gcc로 컴파일까지 완료된 상황이다.
이런 상황에서는 extern "C"를 사용해야 한다.

C++ 소스코드에 extern "C"를 추가하고 똑같이 g++로 컴파일하고 nm으로 살펴보자.

1
2
3
4
5
6
7
8
9
10
11
extern "C" {
int cppfunction1(int a)
{
    return a;
}
}

int cppfunction1()
{
    return -1;
}
1
2
g++ -c cppfunc.cpp
nm cppfunc.o
1
2
0000000000000010 T _Z12cppfunction1v
0000000000000000 T cppfunction1

extern "C"로 감싸진 함수의 이름에 Name mangling기법이 적용되지 않았다.
.cpp 파일에 있지만 .c 파일에 정의된 함수처럼 컴파일된 것을 알 수 있다.


C++에서 C로 컴파일된 함수를 사용하는 예시


위에서 예시로 들었던 상황을 소스코드로 표현해 보면 아래와 같다.

  • cfunction1 함수가 이미 .c 파일에 정의되어 있었고 gcc로 컴파일까지 완료된 상황
1
2
3
4
int cfunction1(int a)
{
    return a;
}
1
2
gcc -c cfunc.c
nm cfunc.o
1
0000000000000000 T cfunction1
  • .cpp 파일에서 extern "C"cfunction1 함수 선언을 감싸고 g++로 컴파일
1
2
3
4
5
6
7
8
9
extern "C" {
int cfunction1(int a);
}

int cppfunction1()
{
    cfunction1(0);
    return -1;
}
1
2
g++ -c cppfunc.cpp
nm cppfunc.o
1
2
3
                 U _GLOBAL_OFFSET_TABLE_
0000000000000000 T _Z12cppfunction1v
                 U cfunction1

cppfunction1 함수는 Name mangling기법이 적용되었고, cfunction1 함수는 적용되지 않은 채로 컴파일되었다.
이제 .cpp 파일에서 .c 파일의 함수를 호출할 수 있게 되었다.


This post is licensed under CC BY 4.0 by the author.

© sirius-mhlee. Some rights reserved.

Using the Chirpy theme for Jekyll.