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 파일의 함수를 호출할 수 있게 되었다.