2

私はVS2010とVS2012の両方のプロジェクトでソリューションに取り組んでいます。

VS2010プロジェクトは、VS2012の関数を呼び出します。その逆も同様です。これは最初は問題なく機能しましたが、両方のプロジェクト間で変数を共有する必要がある場合、変数のメモリアライメントが同じではなく、各プロジェクトが同じメモリアドレスを異なる方法で解釈することに気付きました。

更新STLコンテナ、std::を含まない他の構造体およびクラスを使用している場合にのみ発生するようです。正常に動作します。

問題を説明するために、次のコードは、異なるVisualStudioバージョンで実行したときに異なる結果をもたらすはずです。

#include <string>
#include <vector>

int main()
{
    int stringSize = sizeof(std::string);           // Yelds 32 on VS2010, 28 on VS2012
    int intVectorSize = sizeof(std::vector<int>);   // Yelds 20 on VS2010, 16 on VS2012

    return 0;
};

各バージョンにいくつかの依存関係があるため、両方のプロジェクトを同じバージョンに更新することはまだできません。

誰かが解決策や問題を回避する方法を知っていますか?

できるだけ早く両方のプロジェクトをVS2012コンパイラにアップグレードしますが、今は迅速で汚い解決策を探しているので、作業に取り掛かることができます。STLコンテナでのみ発生するようですが、すべてのプロジェクトで古いバージョンのライブラリを使用することはおそらく可能ですか?または、コンパイラをだますことは可能ですか?おそらくパディングサイズを変更しますか?

また、 std :: vectorの最初の要素は正常に読み取られるようで、ベクトルの後続の要素のみがスクランブルされているようです。(写真を参照してください。

デバッグイメージ

2010年と2012年の両方でコンパイルされた「main.cpp」の「Fetched」変数のデバッグの画像。


誰かが私に変数が共有されている方法を明確にしたかったのです。

最初のプロジェクトをVS2012コンパイルモードでDLLにコンパイルしてから、VS2010でそのプロジェクトにアクセスしようとしています。

問題を再現するためのコードを次に示します。自分で試してみたい場合は、ここから完全なVS2012ソリューションをダウンロードできます。

このコードは、VS2012を使用してDLLにコンパイルされます。

DllExport.h

#ifdef DLLHELL_EX
#define DLL_API __declspec(dllexport) 
#else
#define DLL_API __declspec(dllimport) 
#endif

#include <vector>
#include <string>

class DLL_API Foo
{
public:
    Foo();
    ~Foo();

    std::vector<std::string>* exposedMember;
};

DllExport.cpp

#include "DllExport.h"

Foo::Foo()
{
    // Create member
    exposedMember = new std::vector<std::string>();

    // Fill member with juicy data
    for(int i=0; i<5; i++)
            exposedMember->push_back("Fishstick");
}

Foo::~Foo()
{
    // Clean up behind ourselves like good lil' programmers
    delete exposedMember;
}

このコードはDLLを使用し、VS2010を使用してコンパイルされます。

main.cpp

#include "DllExport.h"

int main()
{
    // Creating class from DLL
    Foo bar;

    // Fetching "exposedMember" from class
    std::vector<std::string>* member = bar.exposedMember;

    return 0;
}

DLLは、このチュートリアルを使用して作成されました

4

2 に答える 2

10

ランタイムの異なるバージョンのタイプを混在させないでください。同じサイズであっても、変数を異なる場所に格納したり、一部のアルゴリズムがわずかに変更されたりする場合があります。タイプがまったく同じであっても、コンパイラーが異なれば、それらを異なる方法で表現することを選択する場合があります。

これを行う良い方法は本当にありません。C ++は、標準ライブラリの実装が変更されないことを保証していません。また、コンパイラは、たとえ同意しなかったとしても、ABIに同意できないようです(同じコンパイラのバージョン間でも)。他の人が使用するAPIを作成する場合、ほとんどの人は完全に自分の管理下にあるCタイプのみをエクスポートすることを選択します。

于 2012-12-30T21:54:40.913 に答える
-2

異なるバージョンを使用しないオプションがないため、問題を解決するのに最も近いのは、 STLコンテナーに直接アクセスするのではなく(たとえば)、 STLコンテナーへのポインターを使用することです。std::vector<std::string*>*std::vector<std::string>*

可能であれば、ポインター以外のソリューションを非常に好むでしょうが、少なくともこの方法では、回避策として独自の文字列とベクトルクラスを発明する必要はありません。

VisualStudio内のポインター


アップデート

人々はどうやらこの答えをあまり好きではなかったようです。個人的には、何かをすべきではないと言われるよりも、解決策があると言われたほうがいいと思います。このソリューションでは、数週間後にすべてを同じコンパイラにアップグレードできるようになるまで作業を続けることができたため、私たちを救いました。

しかし、批判にはいくつかのメリットがあります。解決策は動作するのは非常に危険である可能性があり、構造体の一部としてではなく単独で割り当てられた場合、Stringクラスのレイアウトが両方のコンパイラで同一であるのはおそらく偶然です。

より良い解決策はおそらく単純です:

代わりにCタイプを使用します。たとえば.c_str()、DLLから直接文字列にアクセスする代わりに、C文字列を公開するために使用するか、すべての文字列をC文字列に置き換えます。

これが@CoryNelsonの意味だと思いますがmost people choose to export only C types、当時のCタイプの無知と経験不足のため、理解できず、単に不可能だと言われてバカだったと思いました。しようとしています。

また、反対票を投じる方も、自分で推測するのではなく、その理由を説明していただければ幸いです。理由がわかれば批判は問題ありません。

于 2013-01-01T23:51:47.667 に答える