C 와 C++ 프로그램 링크(link) 방법 [두번째] : C++ 에서 C 의 함수 호출방법

지난 시간에 mangling/demangling 에 대해 알아보았습니다.

자... 이번 시간에는 먼저 c++ 에서  c 의 함수를 호출하는 방법을 알아보도록 하죠.
먼저 지난 시간에 사용한 코드를 gcc 로 컴파일해둡니다.

sh> cat test_func.c
#include <stdio.h>

void test_func(const char * s)
{
    printf("[%s] : [%s]n", __func__, s);
}

sh> gcc -c test_func.c

그런 다음 이를 실제로 호출하는 cpp 프로그램 파일을 만들어보죠.

sh> g++ -c call.cpp
void test_func(const char * s);

int main()
{
    test_func("foon");
    return 0;
}

이제 두개의 object 를 링크하여 call 이라는 실행파일을 만들어봅니다.

sh> g++ -o call test_func.o call.o
call.o: In function `main':
call.cpp:(.text+0xa): undefined reference to `test_func(char const*)'
collect2: ld returned 1 exit status

그런데, 이게 웬일일까요 ?  분명히 test_func.c 에 test_func() 함수를 구현하고 object 까지 만들어뒀는데 해당 함수가 없다고 합니다.

이유는 간단합니다. 지난 시간에 알려드렸던 mangling 을 정확히 이해하고 계셨다면 금방 답을 짐작하셨을 수도 있을겁니다.
컴퓨터는 거짓말을 안합니다. ㅎㅎ ^^

sh> nm test_func.o
000000000000000d r __func__.2044
                 U printf
0000000000000000 T test_func

sh> nm call.o
                 U _Z9test_funcPKc
0000000000000000 T main

위의 nm 결과(symbol table list)를 보세요.
test_func.o 의 symbol table 에는 test_func 라는 이름으로 등록이 되어 있습니다.
그런데, 호출하는 측의 call.o 파일에는 mangling 된 이름으로 등록이 되어 있습니다.
그리고, U 라고 표시되어 있죠. (이건 지난 시간에 다른 object 나 library 에 포함된 symbol 이라고 말씀드렸죠.)
즉, call.o  입장에서는 다른 object 나 dynamic library 파일에 _Z9test_funcPKc 라는 이름으로 등록된 함수를 호출하려고 한다는 의미입니다.
위의 nm 결과를 보면 이런 이름의 함수가 어느 object 에도 없으니 당연히 실패가 되는겁니다.

그럼 이를 어찌해야 하나요 ? 함수이름을 그렇게 지어야 하나 ??? ㅎㅎㅎ
그래서, 등장하는 것이 여러분이 그동안 종종 보아왔을지도 모르는 extern "C" 라는 키워드입니다.
아래의 결과를 한번 위와 비교해보도록 하죠.

sh> cat call.cpp
extern "C" void test_func(const char * s);  # extern "C" 추가

int main()
{
    test_func("foon");
    return 0;
}

sh> g++ -c call.cpp                          # 다시 컴파일
sh> g++ -o call test_func.o call.o           # 링크
sh> nm call.o
0000000000000000 T main
                 U test_func                 # mangling 이 안되어 있음.

코드에 extern "C" 를 추가했더니 링크 시에 발생하던 오류가 사라졌고, call.o 파일의 nm 결과로 나오는 symbol table 에서 test_func 함수의 이름도 mangling 이 안된 상태로 나오는군요.

그러니, call.o 파일에서 test_func.o 파일에 있는 test_func() 함수를 호출하는게 가능하겠네요.

흠...
이의 결과를 보면 extern "C" 의 효과를 짐작해볼 수 있습니다.
extern "C" 는 c++ 컴파일러로 컴파일을 할 때 함수의 인자 등을 고려하지 않고, 즉 mangling 하지 않고 마치 C 함수처럼 취급하여 symbol table 에 남기도록 하기 위한 것입니다.
즉, 이는 컴파일러에서 자료형을 검사하는 안전성 수준을 C 수준으로 떨어뜨리는 것입니다.

간단하게 말하면 C 코드와 C++ 코드 간에 호출을 자유롭게 하려면 당연히 symbol 이름을 같게 만드는 무언가를 적용해야한다는 원리인거죠.

아마 여러분은 아래와 같은 코드를 header 파일에서 수없이 보셨을 겁니다. 이것이 모두 위와 같은 이유로 C 의 헤더파일을 C++ 에서도 문제없이 사용할 수 있도록 미연에 방지하기 위해 넣어두는 것입니다.

#ifdef __cplusplus
    extern "C" {
#endif

void test_func(const char * s);

#ifdef __cplusplus
   }
#endif

You may also like...

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x