2012-02-03 16 views
4

Visual C++コンパイラを使用してアプリケーションをコンパイルしました。プラグインは.dllの形式でロードできます。それはそれがない、まさにかなり重要ではありません、実際には次のようになります。G ++コンパイル済みDLL(プラグイン)をVC++コンパイル済みアプリケーションで使用すると、どのような問題が発生する可能性がありますか?

UML Diagram

これは

など、私の質問をするアプリケーションAPIのオブジェクトへのポインタを返す.dllから関数を呼び出す含みアプリケーションが.dllから関数を呼び出し、そこからポインタを取得してそれを処理するときに、どのような問題が発生する可能性があります。たとえば、私の頭に浮かぶものは、ポインタのサイズです。 VC++とG ++の違いは?はいの場合、これはおそらくアプリケーションをクラッシュさせるでしょうか?

私はVisual Studio IDE(残念なことにアプリケーションSDKを使用するための「好ましい」方法です)を使いたくありません。 VC++のようにG ++をにコンパイルできますか?

PS:私は使用MINGW GNU G ++

+2

"G ++" とは何ですか? GNU C++コンパイラ(「g ++」)は、MinGWのバリエーションです。はい? – selbie

+0

はい、あなたは正しいです。私はこれをこの質問に広告します。 –

+0

送信する構造は、いつでも/マーシャル/(他の多くの名前)をシリアル化することができます。あなたが持っているかもしれない問題を理解するためにちょうどGoogleのC + + stuct埋め込み。あなたがファイルやネットワークのようにデータを扱うなら、あなたは大丈夫でしょう。あなたのヘッダーの細部の角をカットすることができます。ちょうどデータが正しい場所にあることを確認してください(つまりパディングなし) –

答えて

6

アプリケーションとDLLの両方が同じマシンでコンパイルされていて、両方ともC ABIのみを使用している限り、正常であるはずです。

あなたが確かにできないことは、あらゆる種類のC++構造を共有することです。たとえば、メインアプリケーションの配列をnew[]とし、DLLをdelete[]にする必要があります。これは、固定されたC++ ABIが存在しないため、異なるコンパイラがC++データ構造をどのように実装するかを特定のコンパイラが知る方法がないためです。これは、ABI互換ではないMSVC++のさまざまなバージョンでも当てはまります。

+0

私の意見では、これは最もマッチした答えです。ありがとうございました! –

3

すべてのC++言語の機能は、私は怖い、完全に互換性がないことを行っています。名前の変更からメモリー割り当て、仮想呼び出し機構までのすべてが完全に異なり、相互運用可能ではありません。 最高のはあなたが望むことができる、すばやく、慈悲深いクラッシュです。

あなたのコンポーネントがお互いに話すためにextern "C"インターフェイスのみを使用している場合は、おそらくそれを行うことができますが、そこにも注意する必要があります。両方のC++ランタイムには起動コードとシャットダウンコードがあります。アプリケーションをアセンブルするために使用するリンカーによって、このコードを他のコンパイラに組み込む方法を知っているという保証はありません。あなたはかなり多くする必要がありますリンクg ++ - g ++でコンパイルされたコード、例えば。

1つのコンパイラでC++機能を使用し、そのコンパイラのリンカを使用すると、動作する可能性が高くなります。

+1

Downvoters、ハァッ? –

+1

OPは、DLLの形でプラグインを使用することを話しています。これは、Cのデータ構造だけが前後に渡っている限り、常にうまく動作します。 (あなたがリンカについて言ったことは、実際には、ここでは関係ありません。) – markgz

0

主な問題は、関数シグネチャとウェイパラメータがライブラリコードに渡されることです。私は、VC++ dllをgnuベースのコンパイラで過去に動作させることを非常に困難にしてきました。 VC++はいつもお金を払っていました。

私の経験はDirectX APIの経験でした。ゆっくりとサブセットは愛好家によって修正されたバイナリを得ましたが、それは最新のものでも信頼できるものでもありませんでした。評価した後、SDLという適切なクロスプラットフォームAPIに切り替えました。

This wikipedia articleには、ライブラリをコンパイルしてリンクするさまざまな方法が記述されています。私はここで要約できるほど深いです。

1

ポインタのサイズは変化しません。コンパイラではなくプラットフォームとモジュールのビット数に依存します(32ビットと64ビットなど)。

基本的に他のすべてのもののサイズは異なりますが、はどのようなものが異なるのですか?はテンプレートです。

構造体のパディングとアライメントは、コンパイラに依存する傾向があり、多くの場合、コンパイラ内で設定される傾向があります。ポインタは一般的にプラットフォームのビット境界境界にあり、その後は3バイトを持つような緩やかな規則がありますが、それをどのように処理するかはコンパイラによって異なります。

テンプレート、特にSTL(各コンパイラごとに異なる)からのテンプレートは、メンバー、サイズ、パディングなどが異なる場合があります。唯一の標準的な部分はAPIですが、バックエンドはSTL実装に任されています(いくつかの規則がありますが、コンパイラはテンプレートを別々にコンパイルできます)。 1つのビルドからモジュール間でテンプレートを渡すことは十分ではありませんが、異なるコンパイラ間では致命的になることがよくあります。

標準化されていない(ネームマングリング)、または必要性(メモリ割り当て)が非常に特殊なものも互換性がありません。いずれにしても、作成したライブラリを破棄して(デリゲートを取るSTLオブジェクトを使用して)割り当てを行い、エクスポートされたメソッドに装飾されていない名前および/またはCスタイル(extern "C")を使用してエクスポートするだけで、 。

私はコンパイラがvtableの仮想デストラクタをどのように処理しているかを少し忘れているように思います。

オブジェクトの参照のみを渡すことができ、外部から見えるテンプレートを完全に避け、主にポインタとエクスポートまたは仮想メソッドで作業する場合は、大部分の問題を避けることができますほとんどのコンパイラと言語で)。書くのは苦痛かもしれませんが、互換性が必要な場合は可能です。

問題のすべてではないが一部を軽減するために、QtのコアライブラリのようなSTLの代替機能を使用すると、その特定の問題が取り除かれます。古いプロジェクトにQtを投げ込むのは厄介なことですが、「すべてを試してみましょう!!!」よりも膨らんでしまいます。 STL缶を使用するよりも、ライブラリーとコンパイラーのデカップリングに役立ちます。

0

これらの間にCランタイムオブジェクトを渡すことはできません。例えば、FILEバッファを一つにオープンし、それを渡して他のバッファで使用することはできません。相手側に割り当てられたメモリを解放することはできません。

+0

Hm、後者は適用されません。 APIは独自のメモリ構成を実装しています。しかし、アプリケーションから "来る"すべてのオブジェクトは、アプリケーションによって解放され、他の方法ラウンド。最初は何が頭痛になるのですか?例えば。クラスがあります(何か考えてください)、私はG ++でコンパイルされた '.dll'でそれを割り当て、それに対するポインタがアプリケーションに渡されます。 –

+0

フィールドが両側でまったく同じ方法で整列(パック)されていることを前提にして、渡すポインターはOKである必要があります。 –

+0

クラスへのポインタを他の側に渡し、その側で逆参照することはまったく機能しません。 – markgz

3

あなたがしていることを知っているなら、これは問題ありません。しかし、注意すべきことがいくつかあります:

私は、EXEとDLLの間のインタフェースが「C」インタフェースか何かのCOMが唯一のC++クラスが純粋なvirutalインタフェースを介しているようなものだと仮定しています。コンクリートクラスをDLLを使ってエクスポートすると、処理が複雑になります。

  1. 32ビットvs. 64ビット。 32ビットアプリケーションは64ビットDLLをロードしませんし、その逆もありません。それらが一致することを確認してください。

  2. 呼び出し規約。 __cdecl対__stdcall。多くの場合、Visual Studioアプリケーションは、デフォルトの呼び出し規約として__stdcallを想定しているフラグ(または関数プロトタイプでは明示的にsoと表示されている)でコンパイルされます。ですから、g ++コンパイラがEXEが期待する呼び出し型と一致するコードを生成するようにしてください。そうしないと、エクスポートされた関数が実行される可能性がありますが、スタックはリターン時にゴミ箱になることがあります。このようなクラッシュでデバッグした場合、cdeclとstdcallの規約が正しく指定されていない可能性があります。簡単に修正できます。

  3. C-ランタイムは、おそらくEXEやDLLの間で共有されることはありませんので、混ぜると一致しません。 EXE内のnewまたはmallocで割り当てられたポインタは、DLL内でdeleteまたはfreeで解放されてはなりません(またその逆もあります)。同様に、fopen()によって返されたFILEハンドルは、EXEとDLLの間で共有できません。このような事態が発生した場合、クラッシュする可能性があります。私の次のポイントにつながります....

  4. インラインコードのC++ヘッダーファイルは頭痛の原因となり、 3。 DLLとEXEの間のインタフェースが純粋な "C"インタフェースであればOKです。

  5. 名前マングリングの問題。名前のマングリングや先頭のアンダースコアのためにエクスポートされた関数名が一致しない問題に遭遇した場合は、.DEFファイルに修正することができます。少なくとも私は過去にVisual Studioで行ってきたことです。同等のものがg ++/MinGWに存在するかどうかは不明です。以下の例。 "dumpbin.exe/exports"の使い方を学び、正しい名前で関数をエクスポートするDLLを検証できます。 extern "C"を使用すると、これも修正するのに役立ちます。

    EXPORTS 
        [email protected] 
        [email protected]@[email protected] @236 NONAME 
    

それらは私が知っている問題です。 DLLとEXEの間のインタフェースを説明していないので、私はそれ以上のことは言えません。

関連する問題