1

DLL の境界を越えてクラスを渡すことは、C++ の vtable レイアウトが定義されていないため、悪い考えですが、呼び出し規約を明示的に設定し、仮想関数と継承を回避するとどうなるでしょうか?

つまり、DLL を介して次の構造体へのポインタを安全に渡すことができますか?

struct MyStruct {

    int a;
    int b;

    WINAPI MyStruct(int a, int b)
        : a(a), b(b)
    {}

    void WINAPI SetA(int a) {

        this->a = a;
    }
};

このような DLL へのリンクを別のコンパイラ バージョンなどで使用しても安全でしょうか?

4

2 に答える 2

2

あなたのコードは、実際には次の C コードと同等です。

struct MyStruct {
    int a;
    int b;
};

void WINAPI InitMyStruct(struct MyStruct* p, int a, int b)
{
    p->a = a; p->b = b;
}

void WINAPI MyStruct_SetA(struct MyStruct* p, int a)
{
    p->a = a;
}

仮想関数を回避しても、基本的に何も得られません。これらの「同等の」C 関数が何と呼ばれるか (「ネームマングリング」) は依然としてコンパイラに依存するため、互換性のあるコンパイラを使用する必要があります。このミレニアム以降の MSVC のすべてのバージョンは、この点で相互に互換性があります。このミレニアム以降の GCC のすべてのバージョンは、相互に互換性があります。2 つを混在させないでください (リンク時のエラーが発生します)。

他にも問題の原因があります。

パッキング/アラインメントの設定が一致していることを確認してください (ただし、プレーンな C インターフェイスでも同様に行う必要があります)。

ある DLL で「new」を使用し、別の DLL で「delete」を使用する場合、まったく同じバージョンのコンパイラを使用し、DLL ランタイム ライブラリを使用しない限り、問題が発生する可能性があります。そのため、クライアント コードから MyStruct オブジェクトを削除しないnewでください。delete代わりに、DLL 内に関数を用意して、それを実行してください。

インターフェースで標準ライブラリ コンテナーを使用しないでください。DLL とクライアントが同じ標準ライブラリにリンクされていない場合、それらは機能しません。

仮想関数を恐れないでください。

: これらの問題はすべて、理論上は他のプラットフォームにも存在しますが、実際には Linux や Mac OS X との関連性はやや低いようです。

于 2013-06-07T09:07:55.837 に答える