5

C では、ライブラリをリンクし、関連するヘッダー ファイルをインクルードするだけで、それを使用したい任意のクライアント コードから呼び出すことができる共有ライブラリを作成できることに慣れています。ただし、 C++ の ABIは揮発性が高く、非標準であるため、他のソースから関数を確実に呼び出すことはできないと読んだことがあります。

これにより、C と同じくらい普遍的な真の共有ライブラリを作成することは C++ では不可能であると私は信じるようになりますが、実際の実装はそうではないことを示しているようです。たとえば、Node.js は非常に単純なモジュール システムを公開しており、関数を使用してプレーンな C++ 関数 ( なしextern "C") を動的にエクスポートできNODE_SET_METHODます。

C++ API のどの要素を安全に公開できますか? また、C++ コードが C++ コードの他の部分とやり取りできるようにする一般的な方法は何ですか? C++ クラスを公開できる共有ライブラリを作成することは可能ですか? それとも、ABI に一貫性がないため、プログラムごとにこれらのクラスを個別に再コンパイルする必要がありますか?

4

3 に答える 3

4

はい、C++ の相互運用性は難しく、トラップに満ちています。モジュールをビルドするには、まったく同じコンパイラ設定でまったく同じバージョンのコンパイラを使用し、それらがまったく同じ CRT ライブラリと標準 C++ ライブラリを共有するようにする必要があります。これらのルールを破ると、分割の両端で同じレイアウトを持たない C++ クラスが発生し、あるモジュールがオブジェクトを削除するモジュールとは異なるアロケーターを使用してオブジェクトを割り当てるときにメモリ管理に問題が発生する傾向があります。コードが間違ったオフセットを使用してクラス メンバーにアクセスし、メモリ リークやヒープの破損が発生すると、実行時エラーの診断が非常に困難になる問題。

Node.js は、まず何もエクスポートしないことで、これらの問題を回避します。NODE_SET_METHOD() は、あなたが思っていることをしません。関数がスクリプトで呼び出されたときに呼び出される関数ポインターと共に、Javascript エンジンのシンボル テーブルにシンボルを追加するだけです。さらに、これはオープン ソース プロジェクトであるため、同じコンパイラとランタイム ライブラリを使用してすべてをビルドしても問題ありません。

于 2013-06-19T09:42:33.757 に答える
1

これ

たとえば、Node.js は、NODE_SET_METHOD 関数を使用してプレーン C++ 関数 (extern "C" なし) を動的にエクスポートできるようにする非常に単純なモジュール システムを公開します。

extern "C"間違っています。関数内でan を使用していることがinit()わかります。これは明らかに node.js が呼び出しているものであり、公開されていない必要な C++ 関数に関数を転送しています。

この質問で説明されているように、extern "C" 宣言はどのように機能しますか? - コンパイラがコードをコンパイルするとき、関数名、クラス名、および名前空間名をマングルします。これを行う理由は、たとえばオーバーロードされた関数などで、名前の衝突が非常に簡単に発生する可能性があるためです。

詳しくはこちらをご覧ください: http://en.wikipedia.org/wiki/Name_mangling

関数を参照して検索する唯一の方法は、extern "C"宣言が使用されている場合です。これにより、コンパイラは名前をマングルしません。つまり、上記の例では、関数initが次のように呼び出されるinit場所で関数fooが呼び出されます_ugAGE(問題ではないため、人間が消費するものではないため、これを作成しました)

extern "C"要約すると、任意の C++ を他の任意の言語に公開できますが、ライブラリへのエントリ ポイントは、マングルされていない名前を参照する唯一の方法であるため、1 つ以上の 'd グローバル関数である必要があります。

于 2013-06-19T09:08:59.893 に答える