1

私が知る限り、パディングに互換性がある場合、ライブラリ間で構造体を渡すことは安全です。そのため、単一のメンバーを含む構造体を使用してテストを作成しましたが、返された構造体を読み取るときにまだランタイム エラーが発生します。

PluginInterface.h:

#ifndef PLUGIN_INTERFACE_H
#define PLUGIN_INTERFACE_H

typedef struct {
    const char *name;
} DataStruct;

class PluginInterface {
public:
    virtual DataStruct __cdecl getData() = 0;
};

#endif // PLUGIN_INTERFACE_H

Plugin.h:

#ifndef PLUGIN_H
#define PLUGIN_H

#include "PluginInterface.h"

class Plugin : public PluginInterface {
public:
    DataStruct __cdecl getData();
};

#endif // PLUGIN_H

Plugin.cpp:

#include "Plugin.h"

DataStruct Plugin::getData() {
    DataStruct data;
    data.name = "name of plugin";
    return data;
}

extern "C" __declspec(dllexport) PluginInterface* getInstance() {
    return new Plugin;
}

main.cpp:

#include <iostream>
#include "windows.h"
#include "PluginInterface.h"

typedef PluginInterface* (*PluginCreator) ();

int main()
{
    HINSTANCE handle = LoadLibrary("Plugin.dll");
    if (handle == nullptr) {
        std::cout << "Unable to open file!" << std::endl; return 0;
    }

    PluginCreator creator = (PluginCreator)GetProcAddress(handle, "getInstance");
    if (creator == nullptr) {
        std::cout << "Unable to load file!" << std::endl; return 0;
    }

    PluginInterface* plugin = creator();
    if (plugin == nullptr) {
        std::cout << "Unable to create plugin!" << std::endl; return 0;
    }

    DataStruct data = plugin->getData();
    std::cout << "so far so good" << std::endl;

    std::cout << data.name << std::endl; // Access violation

    return 0;
}

VS2012 の実行可能ファイルである mingw でプラグインをコンパイルしました。また、const char* を int に置き換えようとしました。この場合、ランダムな整数が得られます。単一の要素を持つ構造体を渡すのはあまり意味がないことはわかっていますが、それでも何が問題なのか疑問に思っています。

4

1 に答える 1

1

問題は、構造体を値で渡すことではありません。これは、構造体を返す関数が非メンバーの宣言された場合に機能するためextern "C"です。問題は、仮想関数の呼び出しにありますgetData()。あなたの例では、VS2012 コンパイラはオブジェクトへのポインタを介して仮想関数を呼び出すコードを生成しますが、オブジェクトは別のコンパイラによって生成されたコードによって作成されました。C++ ABI が 2 つのコンパイラ間で異なるため、これは失敗します。これは、仮想関数の基になる実装が異なることを意味します。

creator両方のコンパイラが C ABI の同じ基本実装を持っているため、呼び出しは成功します。ライブラリの境界を越えて C++ を使用する場合は、ライブラリが同じ C++ ABI バージョンでコンパイルされていることを確認する必要があります。これは、同じコンパイラの異なるバージョン間で異なる場合があることに注意してください。

于 2013-10-03T11:07:08.233 に答える