c++ 에서 c 함수링크를 사용하는 방법에 대한 방법을 설명한다.

1.  sample.cpp
extern "C" void dbg(const char *s)
int main()
{
dbg("foo");
return 0;
}

2. dbg.c
#include <stdio.h>
void dbg(const char *s)
{
printf(" Log : %s\n", s);
}
3. compile
root@boggle70-desktop:test# ls -la
합계 16
drwxr-xr-x 2 root root 4096 2011-06-04 17:18 .
drwxr-xr-x 3 root root 4096 2011-06-04 17:14 ..
-rw-r--r-- 1 root root   74 2011-06-04 17:06 dbg.c
-rw-r--r-- 1 root root   77 2011-06-04 17:09 sample.cpp
root@boggle70-desktop:test# gcc -Wall -c dbg.c 
root@boggle70-desktop:test# g++ -Wall -c sample.cpp 
root@boggle70-desktop:test# g++ -o sample dbg.o sample.o 
root@boggle70-desktop:test# 
root@boggle70-desktop:test# ls -la
합계 36
drwxr-xr-x 2 root root 4096 2011-06-04 17:19 .
drwxr-xr-x 3 root root 4096 2011-06-04 17:14 ..
-rw-r--r-- 1 root root   74 2011-06-04 17:06 dbg.c
-rw-r--r-- 1 root root  844 2011-06-04 17:18 dbg.o
-rwxr-xr-x 1 root root 8462 2011-06-04 17:19 sample
-rw-r--r-- 1 root root   77 2011-06-04 17:09 sample.cpp
-rw-r--r-- 1 root root 1060 2011-06-04 17:18 sample.o
root@boggle70-desktop:test# ./sample 
LOG : foo

4. 진행과정
위에서 보다 시피 sample 이라는 c++ 에서 dbg 라는 c 함수를 호출하는 구조이고
성공적인 링크를 거쳐 실행이 되는 것까지 확인하였습니다.
이제 이 과정에 숨어 있는 여러가지를 확인하겠습니다.
각 오브젝트의 심볼을 한번 확인해 봅니다.
root@boggle70-desktop:test# nm dbg.o 
00000000 T dbg
U printf
root@boggle70-desktop:test# nm sample.o 
U __gxx_personality_v0
U dbg
00000000 T main
여기서 주의 깊게 볼 것은 sample.o 의 심볼중 dbg 가 관련된 부분입니다.
만약 소스에서 extern "C" 가 선언되지 않으면 어떻게 될까요? 
결과를 보겠습니다.
root@boggle70-desktop:test# nm sample.o 
U _Z3dbgPKc
U __gxx_personality_v0
00000000 T main
dbg 심볼이 보이지 않습니다.
왜냐 하면 c 의 경우 컴파일을 하면 기본적으로 c 의 경우에는 함수명이 심볼이 됩니다.
하지만 c++ 에서는 namespace 정보나 함수인자의 자료형이 포함되기 때문에 위와 같은 형태로 됩니다.
위와 같이 컴파일되면 dbg 심볼을 찾을대 실패하게 됩니다.
그러면 extern "C" 를 하게 되면 링크가 되는 이유는 무엇일가요?
그것은 링크시에 인자의 자료형과 일치여부를 검사하지 않는 것입니다.
즉 dgb 라는 심볼만을 가지고 존재 여부만을 확인을 하기 때문입니다.
자 그럼... 재밌는 코드를 보겠습니다.
 1 extern "C" void dbg(int s);
 2 
 3 int main()
 4 {
 5     int a;
 6     char ray[] = "abcdefg";
 7 
 8     a = (int)ray;
 9     
10     dbg(a);
11     
12     return 0;
13 }
위의 코드는 dbg 함수의 인자형이 원래 것과 틀립니다.
하지만 그 인자에 강제로 ray 라는 배열의 값을 넣어줍니다.
이런 경우 결과는 어떻게 될까요?
root@boggle70-desktop:test# ./sample 
LOG : abcdefg
네... 아주 잘 실행이 됩니다.
그러면 그 값에 아무값이나 넘겨주면 보통은 실행시에 dbg 함수에서는
그 값이 문자열의 포인터로 생각하고 print 를 시도하지만 잘못된 참조로
프로그램은 보통 Segmentation fault를 내고 맙니다.
잘못된 참조는 링크문제를 발생시키지는 않지만 문제를 일으킨다는 것입니다.
c++ 에서 링크에 성공하면 잘못된 자료형에 대한 보호가 된다는 것이 일반적이지만 
extern "C"를 사용하는 경우에는 이런 경우에 해당하지 않습니다.
이러한 상호 참조를 위해서 헤더 파일에서는 아래와 같은 사용을 하게 됩니다.
#ifdef __cplusplus
extern "C" {
#endif
void dbg(const char *s);
#ifdef __cplusplus
}
#endif
이렇게 하면 c++ 참조시에는 extern "C"로 c 에서 참조시에는 함수 원형으로 그대로 참조하게 됩니다.

참고 자료 : Binary Hacks - O'REILLY