객체 지향 C++ 코드용 C 래퍼 API 개발
기존의 C++ API를 둘러싼 일련의 C API를 개발하여 코어 로직(개체 지향 C++로 작성)에 액세스하려고 합니다.이는 기본적으로 C++ 로직을 다른 언어로 사용할 수 있도록 하는 글루 API가 될 것입니다.C를 객체 지향 C++로 감싸는 개념을 소개하는 좋은 튜토리얼, 책 또는 베스트 프랙티스는 무엇입니까?
이것은 수작업으로 실행하는 것은 그다지 어렵지 않지만, 인터페이스의 크기에 따라 다릅니다.C코드 내에서 C++라이브러리를 사용할 수 있도록 하는 것이었기 때문에 SWIG는 큰 도움이 되지 않았습니다(SWIG를 사용할 수 있을지도 모릅니다만, 저는 SWIG 전문가가 아니기 때문에 간단한 것은 아닌 것 같습니다).
결국 우리가 한 일은 다음과 같은 일을 했습니다.
- C에서는 모든 오브젝트가 불투명한 핸들로 전달됩니다.
- 생성자와 파괴자가 순수한 함수로 포장되어 있습니다.
- 멤버 함수는 순수한 함수입니다.
- 기타 빌트인은 가능한 경우 C 등가물에 매핑됩니다.
이러한 클래스(C++ 헤더)는
class MyClass
{
public:
explicit MyClass( std::string & s );
~MyClass();
int doSomething( int j );
}
다음과 같은 C 인터페이스에 매핑합니다(C 헤더).
struct HMyClass; // An opaque type that we'll use as a handle
typedef struct HMyClass HMyClass;
HMyClass * myStruct_create( const char * s );
void myStruct_destroy( HMyClass * v );
int myStruct_doSomething( HMyClass * v, int i );
인터페이스의 실장은, 다음과 같습니다(C++ 송신원).
#include "MyClass.h"
extern "C"
{
HMyClass * myStruct_create( const char * s )
{
return reinterpret_cast<HMyClass*>( new MyClass( s ) );
}
void myStruct_destroy( HMyClass * v )
{
delete reinterpret_cast<MyClass*>(v);
}
int myStruct_doSomething( HMyClass * v, int i )
{
return reinterpret_cast<MyClass*>(v)->doSomething(i);
}
}
캐스팅을 피하기 위해 원래 클래스에서 불투명한 핸들을 추출했습니다(현재 사용하고 있는 컴파일러에서는 동작하지 않는 것 같습니다).C가 수업을 지원하지 않기 때문에 손잡이를 구조화해야 합니다.
이것으로 기본적인 C 인터페이스를 얻을 수 있습니다.예외처리를 통합할 수 있는 한 가지 방법을 보여주는 보다 완전한 예를 원하시면 github에서 제 코드를 사용해 보십시오.https://gist.github.com/mikeando/5394166
여기서 중요한 것은 필요한 모든 C++ 라이브러리를 보다 큰 라이브러리에 올바르게 링크할 수 있도록 하는 것입니다.gcc(또는 clang)의 경우 이는 g++를 사용하여 최종 링크 단계를 수행하는 것을 의미합니다.
나는 마이클 앤더슨의 대답이 옳다고 생각하지만 나의 접근 방식은 다를 것이다.한 가지 더 걱정해야 할 것은 예외입니다.예외는 CABI의 일부가 아니기 때문에 예외는 C++ 코드를 지나도록 할 수 없습니다.헤더는 다음과 같습니다.
#ifdef __cplusplus
extern "C"
{
#endif
void * myStruct_create( const char * s );
void myStruct_destroy( void * v );
int myStruct_doSomething( void * v, int i );
#ifdef __cplusplus
}
#endif
래퍼의 .cpp 파일은 다음과 같습니다.
void * myStruct_create( const char * s ) {
MyStruct * ms = NULL;
try { /* The constructor for std::string may throw */
ms = new MyStruct(s);
} catch (...) {}
return static_cast<void*>( ms );
}
void myStruct_destroy( void * v ) {
MyStruct * ms = static_cast<MyStruct*>(v);
delete ms;
}
int myStruct_doSomething( void * v, int i ) {
MyStruct * ms = static_cast<MyStruct*>(v);
int ret_value = -1; /* Assuming that a negative value means error */
try {
ret_value = ms->doSomething(i);
} catch (...) {}
return ret_value;
}
한층 더 뛰어난 기능:MyStruct의 단일 인스턴스로 필요한 모든 것을 알고 있다면 API로 전달되는 void 포인터에 대처할 위험을 감수하지 마십시오.대신 다음과 같은 작업을 수행합니다.
static MyStruct * _ms = NULL;
int myStruct_create( const char * s ) {
int ret_value = -1; /* error */
try { /* The constructor for std::string may throw */
_ms = new MyStruct(s);
ret_value = 0; /* success */
} catch (...) {}
return ret_value;
}
void myStruct_destroy() {
if (_ms != NULL) {
delete _ms;
}
}
int myStruct_doSomething( int i ) {
int ret_value = -1; /* Assuming that a negative value means error */
if (_ms != NULL) {
try {
ret_value = _ms->doSomething(i);
} catch (...) {}
}
return ret_value;
}
이 API가 훨씬 안전합니다.
하지만 마이클이 언급했듯이 연결은 꽤 까다로울 수 있다.
도움이 되었으면 좋겠다
C++ 코드를 C에 노출시키는 것은 어렵지 않습니다. 단지 파사드 디자인 패턴을 사용합니다.
C++ 코드가 라이브러리에 내장되어 있다고 가정하면, C++ 라이브러리에 있는 하나의 C 모듈을 순수한 C 헤더 파일과 함께 라이브러리에 대한 파사드로 만들면 됩니다.C 모듈은 관련 C++ 함수를 호출합니다.
이렇게 하면 C 어플리케이션과 라이브러리가 노출한 C API에 완전히 액세스할 수 있습니다.
예를 들어, 이것은 Passide 모듈의 예시입니다.
#include <libInterface.h>
#include <objectedOrientedCppStuff.h>
int doObjectOrientedStuff(int *arg1, int arg2, char *arg3) {
Object obj = ObjectFactory->makeCppObj(arg3); // doing object oriented stuff here
obj->doStuff(arg2);
return obj->doMoreStuff(arg1);
}
그런 다음 이 C 함수를 API로 공개하고 Clib로 자유롭게 사용할 수 있습니다.
// file name "libIntrface.h"
extern int doObjectOrientedStuff(int *, int, char*);
이것은 분명히 의도된 예이지만 C++ 라이브러리를 C에 설명하는 가장 쉬운 방법입니다.
방향성에 대한 아이디어를 얻거나 SWIG를 직접 활용할 수 있다고 생각합니다.몇 가지 예를 검토하면 적어도 API를 다른 API로 정리할 때 어떤 것을 고려해야 하는지 알 수 있을 것 같습니다.그 운동은 유익할 수 있다.
SWIG는 C와 C++로 작성된 프로그램을 다양한 고급 프로그래밍 언어와 연결하는 소프트웨어 개발 도구입니다.SWIG는 Perl, PHP, Python, Tcl 및 Ruby와 같은 일반적인 스크립트 언어를 포함하여 다양한 유형의 언어와 함께 사용됩니다.지원되는 언어 목록에는 C#, Common Lisp(CLISP, Allegro CL, CFFI, UFFI), Java, Lua, Modula-3, OCAML, Octabe 및 R 등의 비스크립트 언어도 포함되어 있습니다.또한 해석 및 컴파일된 스킴 구현(Guile, MzScheme, Chicken)도 지원됩니다.SWIG는 높은 수준의 해석 또는 컴파일된 프로그래밍 환경, 사용자 인터페이스를 만들고 C/C++ 소프트웨어를 테스트 및 프로토타이핑하기 위한 도구로 가장 일반적으로 사용됩니다.SWIG는 해석 트리를 XML 및 Lisp s-expression 형식으로 내보낼 수도 있습니다.SWIG는 상업 및 비상업적 용도로 자유롭게 사용, 배포 및 수정할 수 있습니다.
을 '사물의 개념'으로.void *
(C 지향 라이브러리에서는 종종 불투명 유형으로 표시됨) C++에서 알고 있는 모든 정보를 재사용합니다.
SWIG를 사용하는 것이 가장 좋은 답이라고 생각합니다.이것은 바퀴의 재창조를 피할 뿐만 아니라 신뢰할 수 있을 뿐만 아니라 문제를 해결하기보다는 개발의 연속성을 촉진합니다.
고주파 문제는 장기적인 해결책으로 해결할 필요가 있습니다.
언급URL : https://stackoverflow.com/questions/2045774/developing-c-wrapper-api-for-object-oriented-c-code
'programing' 카테고리의 다른 글
Java에서 HTML 문자 엔티티를 이스케이프 해제하려면 어떻게 해야 합니까? (0) | 2022.08.03 |
---|---|
값이 null인 경우 직렬화 중에 필드를 무시하도록 잭슨에게 지시하려면 어떻게 해야 합니까? (0) | 2022.08.02 |
__attribute__((컨스트럭터))는 정확히 어떻게 동작합니까? (0) | 2022.08.02 |
Vue 2용 Vue 3 텔레포트 (0) | 2022.08.01 |
조건부로 송신 버튼을 무효로 하는 방법을 설명합니다. (0) | 2022.08.01 |