<질문>
나는이 사실을 알고.
C ++에서 C 함수 호출 :
내 응용 프로그램이 C ++이고 C로 작성된 라이브러리에서 함수를 호출해야했다면 다음을 사용했을 것입니다.
//main.cpp
extern "C" void C_library_function(int x, int y);//prototype
C_library_function(2,4);// directly using it.
이것은 C_library_function이라는 이름을 엉망으로 만들지 않으며 링커는 입력 * .lib 파일에서 동일한 이름을 찾고 문제가 해결됩니다.
C에서 C ++ 함수 호출 ???
하지만 여기서는 C로 작성된 대형 애플리케이션을 확장하고 있으며 C ++로 작성된 라이브러리를 사용해야합니다. C ++의 이름 변경이 여기서 문제를 일으키고 있습니다. 링커가 해결되지 않은 기호에 대해 불평하고 있습니다. 다른 많은 것들을 깨뜨리기 때문에 C 프로젝트에 C ++ 컴파일러를 사용할 수 없습니다. 탈출구는 무엇입니까?
그건 그렇고 나는 MSVC를 사용하고 있습니다
<답변1>
C ++ 코드의 기능을 노출하려면 C API를 만들어야합니다. 기본적으로 extern "C"로 선언되고 C ++ 라이브러리를 래핑하는 순수 C API (예 : 클래스를 사용하지 않음)가있는 C ++ 코드를 작성해야합니다. 그런 다음 생성 한 순수 C 래퍼 라이브러리를 사용합니다.
C가 객체 지향이 아니더라도 C API는 선택적으로 객체 지향 스타일을 따를 수 있습니다. 전의:
// *.h file
// ...
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
typedef void* mylibrary_mytype_t;
EXTERNC mylibrary_mytype_t mylibrary_mytype_init();
EXTERNC void mylibrary_mytype_destroy(mylibrary_mytype_t mytype);
EXTERNC void mylibrary_mytype_doit(mylibrary_mytype_t self, int param);
#undef EXTERNC
// ...
// *.cpp file
mylibrary_mytype_t mylibrary_mytype_init() {
return new MyType;
}
void mylibrary_mytype_destroy(mylibrary_mytype_t untyped_ptr) {
MyType* typed_ptr = static_cast(untyped_ptr);
delete typed_ptr;
}
void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) {
MyType* typed_self = static_cast(untyped_self);
typed_self->doIt(param);
}
<답변2>
나는 다음과 같은 방식으로 할 것입니다.
(MSVC로 작업하는 경우 GCC 컴파일 명령 무시)
aaa.h, aaa.cpp 파일에 정의 된 AAA라는 C ++ 클래스가 있고 AAA 클래스에 C 코드에 대해 활성화하려는 sayHi (const char * name)라는 메서드가 있다고 가정합니다.
클래스 AAA의 C ++ 코드-순수 C ++, 수정하지 않습니다.
aaa.h
#ifndef AAA_H
#define AAA_H
class AAA {
public:
AAA();
void sayHi(const char *name);
};
#endif
aaa.cpp
#include
#include "aaa.h"
AAA::AAA() {
}
void AAA::sayHi(const char *name) {
std::cout << "Hi " << name << std::endl;
}
C ++에 대해 정기적으로 수행되는 것처럼이 클래스를 컴파일합니다. 이 코드는 C 코드에서 사용될 것이라는 것을 "모릅니다". 명령 사용 :
g++ -fpic -shared aaa.cpp -o libaaa.so
이제 C ++에서도 C 커넥터를 만듭니다. aaa_c_connector.h, aaa_c_connector.cpp 파일에서 정의합니다. 이 커넥터는 AAA의 인스턴스를 사용하고 해당 메서드를 호출하는 AAA_sayHi (cosnt char * name)라는 C 함수를 정의합니다.
aaa_c_connector.h
#ifndef AAA_C_CONNECTOR_H
#define AAA_C_CONNECTOR_H
#ifdef __cplusplus
extern "C" {
#endif
void AAA_sayHi(const char *name);
#ifdef __cplusplus
}
#endif
#endif
aaa_c_connector.cpp
#include
#include "aaa_c_connector.h"
#include "aaa.h"
#ifdef __cplusplus
extern "C" {
#endif
// Inside this "extern C" block, I can implement functions in C++, which will externally
// appear as C functions (which means that the function IDs will be their names, unlike
// the regular C++ behavior, which allows defining multiple functions with the same name
// (overloading) and hence uses function signature hashing to enforce unique IDs),
static AAA *AAA_instance = NULL;
void lazyAAA() {
if (AAA_instance == NULL) {
AAA_instance = new AAA();
}
}
void AAA_sayHi(const char *name) {
lazyAAA();
AAA_instance->sayHi(name);
}
#ifdef __cplusplus
}
#endif
다시 일반 C ++ 컴파일 명령을 사용하여 컴파일합니다.
g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so
이제 C 함수 AAA_sayHi (const char * name)를 구현하는 공유 라이브러리 (libaaa_c_connector.so)가 있습니다. 이제 C 메인 파일을 만들고 함께 컴파일 할 수 있습니다.
main.c
#include "aaa_c_connector.h"
int main() {
AAA_sayHi("David");
AAA_sayHi("James");
return 0;
}
C 컴파일 명령을 사용하여 컴파일 :
gcc main.c -L. -laaa_c_connector -o c_aaa
$ PWD를 포함하도록 LD_LIBRARY_PATH를 설정해야하며 실행 파일 ./c_aaa를 실행하면 예상되는 출력을 얻을 수 있습니다.
Hi David
Hi James
편집하다:
일부 Linux 배포판에서는 마지막 컴파일 명령에 -laaa 및 -lstdc ++가 필요할 수도 있습니다. @AlaaM 덕분입니다. 관심을 끌기 위해
<답변3>
이렇게하려면 C ++로 C 용 래퍼를 작성해야합니다. C ++는 이전 버전과 호환되지만 C는 이전 버전과 호환되지 않습니다.
<답변4>
C ++ API가 C 호환 (클래스, 템플릿 등 없음)이라고 가정하면 다른 방법으로 진행할 때와 마찬가지로 extern "C"{...}로 래핑 할 수 있습니다.
객체 및 기타 귀여운 C ++ 항목을 노출하려면 래퍼 API를 작성해야합니다.
<답변5>
C ++ 함수를 extern "C"(일명 C 스타일 기호)로 내보내거나 .def 파일 형식을 사용하여 C ++ 라이브러리를 만들 때 C ++ 링커에 대한 데코 레이팅되지 않은 내보내기 기호를 정의하면 C 링커가 읽는 데 문제가 없어야합니다.
<답변6>
#include
//////////////
// C++ code //
//////////////
struct A
{
int i;
int j;
A() {i=1; j=2; std::cout << "class A created\n";}
void dump() {std::cout << "class A dumped: " << i << ":" << j << std::endl;}
~A() {std::cout << "class A destroyed\n";}
};
extern "C" {
// this is the C code interface to the class A
static void *createA (void)
{
// create a handle to the A class
return (void *)(new A);
}
static void dumpA (void *thisPtr)
{
// call A->dump ()
if (thisPtr != NULL) // I'm an anal retentive programmer
{
A *classPtr = static_cast(thisPtr);
classPtr->dump ();
}
}
static void *deleteA (void *thisPtr)
{
// destroy the A class
if (thisPtr != NULL)
{
delete (static_cast(thisPtr));
}
}
}
////////////////////////////////////
// this can be compiled as C code //
////////////////////////////////////
int main (int argc, char **argv)
{
void *handle = createA();
dumpA (handle);
deleteA (handle);
return 0;
}
<답변7>
함수 선언 앞에 extern "C"키워드를 붙일 수 있습니다.
외부“C”int Mycpp 함수 ()
{
// 여기에 코드 입력
반환 0;
}
더 많은 예를 보려면 "extern"키워드에 대해 Google에서 더 많이 검색 할 수 있습니다. 몇 가지만 더 할 필요가 있지만 Google에서 많은 예제를 얻는 것은 어렵지 않습니다.
'개발 > C++' 카테고리의 다른 글
C ++ 0x에서 해시 값을 어떻게 결합합니까? (0) | 2020.09.26 |
---|---|
벡터를 함수에 전달하는 방법은 무엇입니까? (0) | 2020.09.26 |
C ++ 함수 템플릿 부분 전문화? (0) | 2020.09.26 |
사용하지 않는 반환 값을 무효화하는 이유는 무엇입니까? (0) | 2020.09.24 |