97

私はこれを知っている。

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を使っています

4

7 に答える 7

115

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<MyType*>(untyped_ptr);
    delete typed_ptr;
 }

 void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) {
    MyType* typed_self = static_cast<MyType*>(untyped_self);
    typed_self->doIt(param);
 }
于 2010-04-30T11:41:00.407 に答える
55

私は次のようにします:

(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 <iostream>

#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 <cstdlib>

#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 に感謝します。注意のために

于 2015-03-22T09:37:23.833 に答える
6

C++ API が C と互換性がある (クラス、テンプレートなどがない) と仮定するとextern "C" { ... }、他の方法で行った場合と同様に、 でラップできます。

オブジェクトやその他のかわいい C++ のものを公開したい場合は、ラッパー API を作成する必要があります。

于 2010-04-30T11:41:10.453 に答える
6

これを行うには、C++ で C のラッパーを作成する必要があります。C++ は後方互換性がありますが、C は前方互換性がありません。

于 2010-04-30T11:43:31.590 に答える
2

C++ 関数を extern "C" (別名 C スタイル シンボル) としてエクスポートするか、.def ファイル形式を使用して、C++ ライブラリを作成するときに C++ リンカー用の装飾されていないエクスポート シンボルを定義します。

于 2010-04-30T11:40:10.093 に答える