일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 비교 함수 객체
- reference
- lua
- UE4
- operator new
- 오블완
- Smart Pointer
- 언리얼
- effective stl
- 게임
- 영화 리뷰
- c++
- 암시적 변환
- more effective c++
- 참조자
- 다형성
- 반복자
- 상속
- 루아
- 함수 객체
- 예외
- 영화
- resource management class
- 티스토리챌린지
- exception
- 메타테이블
- implicit conversion
- 스마트 포인터
- virtual function
- Effective c++
Archives
- Today
- Total
스토리텔링 개발자
[More Effective C++] 34. C++, C 혼용하기 본문
728x90
항목 34. 한 프로그램에서 C++와 C를 함께 사용하는 방법을 이해하자.
네임 맹글링(Name Mangling)
- C++ 컴파일러가 내부 호출용 이름을 만들어 함수마다 붙이는 동작.
- 이 동작은 C에서는 발생하지 않는다.
- C에서는 함수 오버로딩이 발생하지 않기 때문이다.
- 즉, 이름이 같은 함수란 존재하지 않는다.
- 하지만 C++에서는 이름이 같은 함수를 부지기수로 볼 수 있다.
- 사실, 오버로딩된 함수는 링커를 통과할 수 없다.
- 같은 이름의 여러 함수를 구분할 수 없기 때문이다.
- 그렇기 때문에 네임 맹글링을 사용한다.
- C로 제작한 라이브러리 함수를 C++에서 사용한다면?
- 아래와 같은 C 라이브러리가 있다면..
void drawLine(int x1, int y1, int x2, int y2);
// C++ 컴파일러가 네임 맹글링으로 내부 호출용 이름으로 바꿔버린다!!
// 예컨대 xyzzy 라는 이름으로 네임 맹글링을 해버렸다면..
drawLine(a, b, c, d); // 맹글링되지 않은 함수 이름으로 호출
// 이는 컴파일러에 의해 아래처럼 바뀐다.
// xyzzy(a, b, c, d); // 맹글링된 함수 이름으로 호출
// 하지만 C 라이브러리 내부에선 맹글링 되지 않은 이름(drawLine)으로 호출하는데
// (C 라이브러리이기 때문에 맹글링되지 않는다.)
// 이로 인해 링크 에러가 발생하게 된다.
- 즉, C++ 컴파일러가 생성하는 목적 파일에는 맹글링되지 않은 이름의 C 함수를 호출하도록 해야 한다는 뜻이다.
// drawLine란 이름의 함수를 선언하되,
// 이 이름은 맹글링되지 않는다.
extern "C"
void drawLine(int x1, int y1, int x2, int y2);
- extern "C"의 의미
- 이 함수가 C로 작성되었다는 주장이 아니다.
- 이 함수가 C로 작성된 함수처럼 호출되어야 한다는 뜻이다.
- 아무튼 확실한 건 네임 맹글링을 막아준다는 것.
- 어셈블러로 만들더라도 네임 맹글링은 되면 안되므로 extern "C"를 붙여주자.
// 이 함수는 어셈블러로 만들어졌다.
// 맹글링되지 않도록 한다.
extern "C" void twiddleBits(unsigned char bits);
- C++ 함수 역시 extern "C"로 선언이 가능하다.
- 왜 필요하냐면, 다른 언어에서 해당 라이브러리를 쓰고 싶을 수 있기 때문.
// C++ 이외의 프로그래밍 언어에서 할 수 있도록, 맹글링을 막는다.
extern "C" void simulate(int iterations);
- extern "C"는 중괄호로 묶어줄 수도 있다.
extern "C"
{
void drawLine(int x1, int y1, int x2, int y2);
void twiddleBits(unsigned char bits);
void simulate(int iterations);
...
}
- C++와 C를 동시에 사용하는 경우
- C++ 컴파일러로 컴파일할 때는 extern "C"가 작동되고
- C 컴파일러로 컴파일할 때는 extern "C"가 드러나지 않도록 하기.
- __cplusplus 전처리자를 사용하여 처리한다.
#ifdef __cplusplus
extern "C"
{
#endif
void drawLine(int x1, int y1, int x2, int y2);
void twiddleBits(unsigned char bits);
void simulate(int iterations);
...
#ifdev __cplusplus
}
#endif
- 주의 사항
- C++ 컴파일러의 "표준" 네임 맹글링 알고리즘 같은 것은 없다.
- 즉, 호환되지 않는 C++ 컴파일러로 생성한 목적 코드는 섞어 사용하면 링크 에러가 발생한다.
정적 데이터 초기화(Initialization of Statics)
- 정적 데이터 초기화란?
- main 함수가 실행되기 전에
- 정적 클래스 객체
- 전역 객체
- 네임 스페이스와 파일 범위에 있는 객체
- 의 생성자가 실행되는 것을 말한다.
- main 함수가 실행되기 전에
- 개발자들은 main이 가장 먼저 실행된다고 가정하기 때문에 C++ 컴파일러는..
- main의 시작 부분에 정적 데이터 초기화를 수행하는 전용 함수 호출 코드를 삽입한다.
- main의 마지막 부분에는 정적 데이터 소멸을 수행하는 함수를 삽입한다.
int main(int argc, char* argv[])
{
performStaticInitialization(); // 컴파일러가 생성한 코드
main에 개발자가 써넣는 코드들...
performStaticDestruction(); // 컴파일러가 생성한 코드
}
- 이는 즉, main이 C++로 작성되지 않으면 정적 객체의 초기화 및 소멸이 이루어지지 않는다는 뜻이다.
- 그러므로 C++를 사용한다면 main은 C++로 작성하는 것이 좋다.
- 프로그램의 대부분이 C여서 main을 C로 작성해야 합당할 것 같을 때라도 그렇게 하자. 정적 객체는 언제 생길지 모른다.
- C로 만든 main에 새 이름을 할당해주고
- C++로 만든 main에서 해당 함수를 호출해주는 식으로 변경하자.
-
extern "C" int realMain(int argc, char* argv[]); // C로 구현한 main int main(int argc, char* argv[]) // C++로 구현한 main { return realMain(argc, argv); }
동적 메모리 할당(Dynamic Memory Allocation)
- C++에서 만든 객체는 new / delete를 사용하고(항목 8 참조)
- C에서 만든 객체는 malloc(calloc) / free를 사용하자.
- 각 페어를 맞게 사용하는 한 문제는 없다.
- 하지만 짝을 잘못 맞춰 사용하는 경우 문제가 발생한다.
- 이 룰을 실천하기 힘든 상황이 있다.
// ps가 가리키고 있는 문자열을 별도의 힙 메모리에 복사하고
// 그 포인터를 반환한다.
char* strdup(const char* ps);
// 리턴값의 해제는 사용자 측에서 해줘야 하는데..
// delete를 써야 할까, free를 써야 할까?
자료구조의 호환성(Data Structure Compatibility)
- C++와 C 프로그램 사이에 데이터를 주고받을 수 있을까?
- C는 C++의 기능을 이해할 수 없는 것이 당연하므로, C 언어가 이해 가능한 개념만 넘길 수 있다.
- 즉, 멤버 함수 포인터나 객체를 C에 넘기는 건 불가능하다.
- 하지만, raw 포인터나 구조체, 기본 제공 타입은 넘길 수 있다.
- 구조체
- C와 C++은 메모리 배열 구조가 동일하므로 안전하게 오갈 수 있다.
- 함수가 들어 있더라도 가상 함수만 아니면 메모리 배열 구조는 변하지 않는다.
- 즉, 비가상 함수만 가지고 있는 객체는 멤버 함수가 지원되지 않는 C에서도 사용할 수 있다.
- 하지만 가상 함수가 포함되면 가상 함수 테이블 때문에 C++ 구조체의 메모리 배열이 C와 달라진다.(항목 24 참조)
- 또한 상속 구조를 가진 구조체도 메모리 구조가 변경되므로 C에서 사용하기 힘들다.
- C++와 C에서 동시에 컴파일 되는 자료구조는 호환성이 있다고 할 수 있다.
728x90
'개발 > More Effective C++' 카테고리의 다른 글
[More Effective C++] 35. C++98 표준 (0) | 2024.10.23 |
---|---|
[More Effective C++] 33. 추상 클래스(abstract class) (0) | 2024.10.17 |
[More Effective C++] 32. 미래 지향적 프로그래밍 (2) | 2024.10.16 |
[More Effective C++] 31. 다중 디스패치(multiple dispatch) (0) | 2024.10.07 |
[More Effective C++] 30. 프록시 클래스 (0) | 2024.10.04 |
Comments