♧ C로 작성된 함수를 C++에서 호출하고자 할 경우,
혹은 반대로 C++로 작성된 함수를 C프로그램에서 호출하고자 할 경우.
[ C/C++와 심볼명 ] |
|||||||
▷ 아래의 dbg 함수를 C/C++컴파일러로 각각 컴파일해 보자.
# C 컴파일 :: gcc -W -Wall -c dbg.c # C++ 컴파일 :: g++ -W -Wall -c dbg.c
▷ C컴파일 / 심볼명 확인
▷ C++컴파일 / 심볼명 확인
▷ 컴파일해서 생성된 오브젝트 파일에 포함된 심볼명.
☞ C 컴파일러로 함수를 컴파일 하면 기본적으로는 함수명이 그대로 심볼명이 된다. 시스템 환경에 따라서는 심볼명이 "dbg"가 아니라 "_dbg"가 될 경우도 있지만 크게 다르지는 않다. 한편, C++ 컴파일러로 함수를 컴파일한 경우 함수가 속한 이름공간(namespace) 정보 또는 함수 인자의 자료형 정보가 심볼명에 포함되어 나타난다.
|
[ C++에서 C함수 호출하기 ] |
|||
▶ dbg.c를 C컴파일러로 컴파일한 후 C++로 작성된 함수(sample.cpp)에서 호출해 보자. ① sample.cpp 작성
② sample.cpp 컴파일, 링크하면 정상적으로 실행 파일이 생성/실행
이상 없이 C++함수(sample.cpp)에서 C함수(dbg)를 호출 하였다. ☞ sample.cpp의 『extern "C"』가 포인트다.
▶ 『extern "C"』의 유무에 따라 sample.o의 변화. ① 『extern "C"』가 있을 경우.
② 『extern "C"』가 없을 경우.
☞ ②에서 "sample.o"는 "_z3dbgPKc"라는 심볼을 참조하지만, dbg.o에 포함된 심볼은 단지 "dbg"로 "_z3dbgPKc"는 심볼은 어디에도 없다.
▷ 따라서 『extern "C"』를 넣지 않으면 다음과 같이 링크할 때 실패하게 된다.
이와 같이 C++에서 C함수를 호출할 때 『extern "C"』가 중요한 역할을 한다.
▶ 〔주의〕 extern "C"를 붙이면 인자의 자료형 일치 여부를 검사하지 않는다. ① sample.cpp의 dbg자료형 변경.
② 컴파일, 링크, 실행.
☞ 정상적으로 링크는 되지만 생성된 실행 파일은 정상적으로 실행 되지 않는다.
▶ 〔왜! 링크는 성공한 것일까?〕 sample.o가 참조하고 있는 것은 어디까지나 자료형 정보를 포함하지 않은 심볼 "dbg"로, dbg.o에 포함되어 있는 심볼명과 일치하기 때문이다. "링크에 성공하면 잘못된 자료형으로 함수가 호출되지 않는다."라고 생각하기 쉽지만, C++라도 extern "C"를 사용한 부분인 경우에 한해서는 그렇지 않다. 이는 컴파일러에서 자료형을 검사하는 안전성 수준이 C언어 수준으로 저하되기 때문이다.
▷ 이러한 문제를 미연에 방지하려면 C언어 측의 헤더 파일을 C++에서도 이용할 수 있도록 준비해 두어야 한다. 예를 들면, 아래의 dbg.h와 같은 헤더 파일을 작성하는 것이 바람직하다.
|
[ C에서 C++함수 호출하기 ] |
|||
▷ 이번에는 반대로 C에서 C++ 함수를 호출해 보도록 하자. 『최대공약수를 구하는 함수』를 Boost C++ Library를 이용해 C++로 간단히 구현하고, 그 함수를 C에서 호출해 보자.
▶ 〔중요한 점 두가지〕 º 링크는 gcc가 아닌, g++로 수행.
▷ C++측 구현
▷ C++함수를 호출하는 C프로그램은 특별히 달라진 것이 없다.
▶ 컴파일, 실행.
|
〔 주의 사항 〕 |
||
▶ C++함수는 C함수로 예외 처리를 넘겨서는 안됨. C언어에서 호출되는 C++함수를 작성할 때는 C++의 예외가 C함수로 도달하지 않도록 주의. C++의 예외가 C언어로 작성된 함수에 도달된 경우의 함수 동작에 대해 C++표준 규격에는 명확히 정의되어 있지 않다. 예를 들면 GCC에서는 프로세스가 이상 종료되는 현상이 나타남. C++ 함수에서 명시적인 예외를 throw하지 않도록 신경 쓰는 것은 물론, ▷ 다음과 같은 점도 충분히 주의해야 한다. º new 연산자가 std::bad_alloc 예외를 throw할 가능성 º std::vector의 멤버 함수 at에서 std::out_of_range 예외를 throw할 가능성
▶ 함수 포인터를 다루는 C함수에 주의. C함수 내부에서 C++의 예외가 발생하는 것을 막을 수 없는 경우가 있다. 다음과 같이 표준 C의 qsort함수를 C++에서 사용한 경우를 생각해 보자.
☞ qsort 함수에 인자로 넘긴 비교함수 compar가 예외를 throw하기 때문에 qsort함수내부에서 C++의 예외가 발생하게 된다. GCC를 사용할 경우에 이와 같은 경우라도 프로세스가 이상 종료되지 않기 위해서는 아래와 같이 qsort 함수를 "-fexceptions"옵션을 지정해서 컴파일 해야 한다.
일반적으로 함수 포인터를 다루는 C함수는 -fexceptions옵션을 지정해서 컴파일해야 오류가 발생하지 않는다. glibc의 Makefile을 보면 이러한 함수(qsort, bsearch 등)는 이 옵션을 지정해서 컴파일 하도록 되어 있다. |
'컴퓨터 서적 정리 > Binary Hacks' 카테고리의 다른 글
[Hack #20] 공유 라이브러리에 PIC를 사용하는 이유 (1) | 2011.07.05 |
---|---|
[Hack #19] 링크할 때 심볼 충돌 방지하기 (0) | 2011.07.04 |
[Hack #17] ar - 정적 라이브러리 다루기 (0) | 2011.07.04 |
[Hack #16] strip - 오브젝트 파일에서 심볼 삭제 (0) | 2011.07.04 |
[Hack #15] addr2line - 주소에서 파일명과 행 번호 얻기 (0) | 2011.07.03 |