이글은 예전 제 싸이월드 블로그에 작성한 글을 티스토리로 옮긴 것입니다.
원문 : http://cy.cyworld.com/home/21147242/post/4E4A12146415739A07C68401
원문 작성일 : 2011.08.16
------------------------------------------------------------------------
아래 테스트는 리눅스 환경에서 테스트하였습니다.
C++ 에서 작성된 myList.h, myList.cpp 라는 파일이 있다고 가정합니다.
c 로 작성된 main.c 파일이 있습니다.
main.c 가 myList.h 파일을 include 하여 해당 기능을 수행할 수 있도록 함이 목적입니다.
어떤 C++ 코드를 하나 만들어 봅니다.
C 에서의 사용을 고려하지 않은 C++ 코드는 아래와 같습니다.
=================================== myList.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
#ifndef _MYLIST_H_
#define _MYLIST_H_
#include<list>
using namespace std ;
typedef list<int>MyList ;
typedef list<int>::iterator MyListIter ;
class CMyList
{
public :
int addList(int val) ;
int getSize() ;
private :
MyList m_list ;
MyListIter m_listIter ;
};
#endif // _MYLIST_H_
|
======================================= myList.cpp
1
2
3
4
5
6
7
8
9
10
11
12 |
#include "myList.h"
int CMyList::addList(int val)
{
m_list.push_back(val) ;
return 1 ;
}
int CMyList::getSize()
{
return m_list.size() ;
} |
위 코드를 gcc로 컴파일하면 당연히 에러가 나겠죠.
아래와 같이 C 에서 컴파일할 수 있도록 작업을 해 줍니다.
1. C++ 전용(?) 코드는 #ifdef __cplusplus 로 막아줍니다.
위 코드에선 STL 선언부랑 클래스 선언부가 해당될 겁니다.
2. C 에서 호출할 수 있도록 함수를 추가하여줍니다.
int MyList_addList(int val) ;
int MyList_getSize() ;
3. 구현부에서 name magling 이 안일어나도록 extern "C" 를 선언해 줍니다.
위 조건대로 수정하면 아래와 같이 수정될 것입니다.
=============================================== myList.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 |
#ifndef _MYLIST_H_
#define _MYLIST_H_
#ifdef __cplusplus
#include<list>
using namespace std ;
typedef list<int> MyList ;
typedef list<int>::iterator MyListIter ;
class CMyList
{
public :
int addList(int val) ;
int getSize() ;
private :
MyList m_list ;
MyListIter m_listIter ;
};
#else
void* MyList_getInstance() ;
int MyList_addList(void* instance, int val) ;
int MyList_getSize(void* instance ) ;
void TEST_destory(void* instance) ;
#endif
#endif // _MYLIST_H_ |
================================================= myList.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 |
#include "myList.h"
int CMyList::addList(int val)
{
m_list.push_back(val) ;
return 1 ;
}
int CMyList::getSize()
{
return m_list.size() ;
}
extern "C"
{
void* MyList_getInstance()
{
CMyList* myList= new CMyList ;
return (void*)myList ;
}
int MyList_addList(void* instance, int val)
{
CMyList * myList = (CMyList*)instance ;
myList->addList(val) ;
return 1 ;
}
int MyList_getSize(void* instance )
{
CMyList* myList = (CMyList*)instance ;
return myList->getSize() ;
}
int MyList_destroy(void* instance)
{
CMyList* myList = (CMyList*)instance ;
delete myList ;
}
} |
이제 C 전용(?)으로 선언된 아래 함수를 가지고 main.c 에서 써먹어 봅니다.
void* MyList_getInstance() ;
int MyList_addList(void* instance, int val) ;
int MyList_getSize(void* instance ) ;
void TEST_destory(void* instance) ;
=============================================== main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
#include<stdio.h>
#include "myList.h"
int main()
{
void* myList = MyList_getInstance() ;
int size = 0;
MyList_addList(myList, 3) ;
MyList_addList(myList, 8) ;
size = MyList_getSize(myList) ;
printf("size : %d\n", size) ;
MyList_destroy(myList) ;
return 1 ;
} |
C++ 의 클래스 객체를 void* 로 대체하였습니다. 핸들처럼요.
C 나 C++ 컴파일러는 object 파일을 생성하는데 이 object 파일은 C, C++ 모두 공통으로 사용할 수 있습니다.
그래서 위와같이 살짝 수정하여 서로 호출이 가능할 수 있습니다.
정리하면,
1. 헤더파일의 C++ 코드는 C 컴파일러가 안보이도록 막고,
막은 부분을 대처할 수 있는 함수를 만들어줍니다.
#ifdef __cplusplus 부분이 이에 해당합니다.
2. C++ 컴파일러는 함수 오버로딩 때문에 함수 이름을 변경하여 object 파일을 생성합니다.
(Name mangling 관련 부분은 여기서 자세히 언급하지 않겠습니다.)
하지만 C 컴파일러는 함수 오버로딩을 지원하지 않습니다.
예들 들어,
test()
란 함수가 있다고 하면,
이를 C++ 컴파일러로 컴파일하면
testzx6e()
->이런식으로 변경되어 object 파일에 저장됩니다.
C 컴파일러로 컴파일하면
test()
그대로 저장됩니다.
즉, C 컴파일러는 사용자가
test()
라고 호출하면 object 파일에서 직관적으로
test()
를 찾습니다.
그런데 만약 object 파일을 C++ 컴파일러로 컴파일했다면...
test()
함수가
testzx6e()
로 저장되어있기에 C 컴파일러는
testzx6e()
->이 함수를 못찾겠죠.
이 때 사용하는 방법이, C++ 컴파일러에게, 이 파일들은 C 에서 사용될 예정이니
name mangling 을 수행하지 마라, 즉 object 파일 생성 시,
test()
는
test()
로 저장하라고 알려주는거죠.
이게 myList.cpp 의
extern "C"
부분입니다.
C++ 코드는 object 로 먼저 생성을 해야 C 에서 사용할 수 있습니다.
이제 마지막으로 Makefile 을 작성합니다.
최종 실행파일 생성 시, -lstdc++ 하는 부분에 주의합니다.
================================================= Makefile
main : myList.o main.c
gcc -o $@ $^ -lstdc++
myList.o : myList.cpp
g++ -c -o $@ $^
clean :
rm -rf *.so *.o
=====================================================
-lstdc++ 부분은 아래 홈페이지에서 정보를 얻었습니다.
아래 분께서는 저와는 다른 방법 (구조체를 클래스처럼 쓰셨네요.) 으로
C에서 C++ 을 호출하고 계시니 참고하여 읽어보시기 바랍니다.
'삽질미학 > C,C++' 카테고리의 다른 글
TDES-ECB 암호화 코드 (0) | 2016.10.24 |
---|---|
리눅스 getch() 모듈화하기 (0) | 2016.10.20 |
C 에서 STL map 컨테이너를... - SCL 소개 (0) | 2016.10.14 |
C 코드로 C++ 의 다형성 흉내내기 (0) | 2016.10.14 |
map 컨테이너를 이용해 클래스 멤버함수의 콜백함수 등록과 호출하기 (0) | 2016.10.14 |