programing

C에서 C++를 우아하게 호출하다

projobs 2022. 10. 11. 21:53
반응형

C에서 C++를 우아하게 호출하다

우리는 몇 가지 프로젝트를 평이하게 전개한다.C(C99). 단, 소스코드(수학 라이브러리)로서 라이브러리 1개가 있습니다.C++이 라이브러리가 필요하기 때문에 이 소스코드를 통합하는 가장 우아한 방법은 무엇일까요?

크기 간 비율C그리고.C++20:1그래서 로 이동한다C++선택사항이 아닙니다.정적 라이브러리를 사용할까요? DLL? (모두 Windows에 있습니다.)

편집: 코멘트에 기재되어 있는 내용에 근거해, C호환으로 분할하는 것을 지적합니다.struct duck및 파생된class Duck아마 불필요할 겁니다.구현은 아마 안전하게 에 삽입할 수 있을 것입니다.struct duck제거하다class Duck이 때문에 불필요합니다.real(…)하지만 저는 C++에 대해 잘 모릅니다(특히 C가 C 우주와 상호작용하는 방식).


단순히 모든 C와 C++ 코드를 하나의 바이너리로 링크할 수 없는 이유는 없습니다.

C++ 코드에 인터페이스 하려면 C++ API를 C API로 랩해야 합니다.내부 함수를 여러 개 선언하면 이 작업을 수행할 수 있습니다.extern "C" { ... }C++ 코드를 컴파일 할 때 및 C 클라이언트 코드를 컴파일 할 때 외부 선언을 하지 않습니다.예:

#ifdef __cplusplus
extern "C" {
#endif

typedef struct duck duck;

duck* new_duck(int feet);
void delete_duck(duck* d);
void duck_quack(duck* d, float volume);

#ifdef __cplusplus
}
#endif

C++ 소스에서 오리 구조를 정의할 수 있으며, 실제 오리 구조를 상속할 수도 있습니다.Duckclass from it:

struct duck { };

class Duck : public duck {
public:
    Duck(int feet);
    ~Duck();

    void quack(float volume);
};

inline Duck* real(duck* d) { return static_cast<Duck*>(d); }

duck* new_duck(int feet) { return new Duck(feet); }
void delete_duck(duck* d) { delete real(d); }
void duck_quack(duck* d, float volume) { real(d)->quack(volume); }

duck structure에서 상속을 원하는 유일한 이유는 C API의 속성에 일부를 노출하기 위해서입니다.이것은 일반적으로 나쁜 스타일로 간주됩니다.상속을 하지 않으면 C 헤더는 다음과 같이 됩니다.

struct Duck;

struct Duck* new_Duck(int feet);
void delete_Duck(struct Duck* d);
void Duck_quack(struct Duck* d, float volume);

이는 유형 캐스팅이 필요 없는 해당 구현입니다.

extern "C" {
#include "Duck.h"
}

class Duck {
public:
    Duck(int feet) : {}
    ~Duck() {}

    void quack(float volume) {}
};

struct Duck* new_Duck(int feet) { return new Duck(feet); }
void delete_Duck(struct Duck* d) { delete d; }
void Duck_quack(struct Duck* d, float volume) { d->quack(volume); }

마찬가지로 C++ 인터페이스(순수 가상 클래스)와 그 실장용으로 C API를 작성할 수 있습니다.이 경우 컨스트럭터만 구체적인 구현에 기초하면 됩니다(예를 들어 new_RubberDuck(2)).디스트럭터 및 기타 모든 함수는 C++와 같이 올바른 구현에서 자동으로 동작합니다.

C++ 연산 라이브러리는 유틸리티 클래스의 용으로 실장할 수 있습니다(스태틱멤버만).이 경우 훨씬 더 간단한 접근법을 취할 수 있습니다.

class FPMath {
public:
    static double add(double, double);
    static double sub(double, double);
    static double mul(double, double);
    static double div(double, double);
};

C 인터페이스의 헤더는 다음과 같습니다.

double FPMath_add(double, double);
double FPMath_sub(double, double);
double FPMath_mul(double, double);
double FPMath_div(double, double);

대응하는 실장은 다음과 같습니다.

double FPMath_add(double a, double b) { return FPMath::add(a, b); }
double FPMath_sub(double a, double b) { return FPMath::sub(a, b); }
double FPMath_mul(double a, double b) { return FPMath::mul(a, b); }
double FPMath_div(double a, double b) { return FPMath::div(a, b); }

하지만 어쩌면 이건 당연한 걸 말하는 것일 수도 있어...

일부 객체의 멤버 함수를 직접 호출할 수 있는 "해크"를 만드는 방법이 있습니다.

할 은 '만들기'를 입니다.extern "C" 출하시 함수: 포인터를 합니다(「」로서).void*을 사용하다

두 번째로 필요한 것은 멤버 기능의 이름이 뒤죽박죽이 되어 있는 것입니다.

그런 다음 망진된 이름을 사용하여 함수를 호출할 수 있으며 공장에서 반환된 포인터를 첫 번째 인수로 전달합니다.

경고:

  • 물론 다른 오브젝트, 참조, 기타 C++를 필요로 하는 멤버 호출 함수나 C타입과 호환되지 않는 오브젝트 또는 타입을 반환하는 함수는 동작하지 않습니다.
  • 호출되는 가상 함수가 아니더라도 가상 함수가 포함된 개체에서는 작동하지 않습니다.
  • 뭉개진 이름은 유효한 C 기호여야 합니다.
  • 더 많은...

이것은 추천할 만한 것이 아닙니다.사실 그 반대입니다.저는 이 답변에 나와 있는 것과 같은 것을 하지 말 것을 강력히 권합니다.이는 지원되지 않고 아마도 정의되지 않은 행동이며 이상하고 예측할 수 없는 방식으로 부서질 수 있습니다.

언급URL : https://stackoverflow.com/questions/7281441/elegantly-call-c-from-c

반응형