0

立ち往生していて、これを解決する方法がまったく見つからないため、解決すべき複雑な問題があります。これがコードです

struct MyStruct
{
    int x;    
    float y;
    char c;
};

void foo(MyStruct a_myStruct);

int _tmain(int argc, _TCHAR* argv[])    
{
    void *pMyStruct = malloc(sizeof(MyStruct));
    int* pInt = (int*)pMyStruct;

    *pInt = 10;    
    pInt++;

    float *pFloat = (float*)pInt;    
    *pFloat = 2.545;   
    pFloat++;

    char *pChar = (char*)pFloat;
    *pChar = 'c';

    _asm
    {
        pMyStruct
        call foo
    }

    return 0;
}

void foo(MyStruct a_myStruct)
{
}

ここでfooは、 がスタック上のオブジェクトを操作しており、呼び出されたときにスタック オブジェクトがマップされることを期待していることがわかりますfoo。しかし、残念ながら、MyStructコンパイル時にタイプがわからないため、メモリのブロックを作成する必要があり、実行時にそのブロック内にデータが入力され、foo上記のように asm で呼び出されたときに渡されます。

ヒープ void ポインターをスタック型オブジェクトに変換するにはどうすればよいですか。どういうわけか のa_myStruct引数のアドレスを取得すると、その場所fooを指すことができますが、型のオブジェクトに変換されるようにvoid*逆参照することはできません。void*MyStruct

問題を解決する他の方法はありますか?C++ と同様に、実行時に型を決定することもできます。


C++ で実行時に関数を呼び出す際に問題があり、コンパイル時に不明なユーザー定義型が完全に署名されている可能性があります。またはDIA SDKから)。しかし、主な問題は、実行時にこれらの関数を呼び出したいということです。コンパイル時に、関数のアドレスと、その関数シグネチャの引数として参加しているオブジェクトまたはポインターのユーザー定義型の詳細を取得します。実行時にその関数を呼び出したい場合は、最初にヒープに一時ブロックを作成し、そのブロックにデータを入力して、実行時にその型を設定する必要があります。その型のすべての詳細があります。

ここでの問題は、関数が引数をその型のポインターとして使用できるかどうか、またはその引数が正確にその型のスタックオブジェクトであるかどうかがわからないことです。その型へのポインタがあれば問題ありませんが、そこにオブジェクトがある場合、実行時にその関数を呼び出すのに大きな問題があります。

4

2 に答える 2

1

あなたが提供した追加情報があっても、私はあなたの質問を完全には理解していないことを認めなければなりません. しかし、スタックとヒープと C++ について一般的なことを言いましょう。

引数が関数に渡される方法は、特定の C++ コンパイラの実装の詳細です。これは、C++ コンパイラごとに異なる場合があります。引数が関数に渡される方法は、呼び出し規約と呼ばれます。一部のコンパイラは、引数の受け渡しにスタックもヒープも使用しません。代わりに、可能であれば CPU レジスタを使用します。(Watcom の C++ コンパイラは、引数を関数に渡すためにレジスタを優先するコンパイラの顕著な例です。)

これは、どの C++ コンパイラも、別の C++ コンパイラとバイナリ互換性のないバイナリを作成する可能性があることを意味します。(C++ 言語標準は、コンパイル済み出力のバイナリ標準を規定していないため、異なるコンパイラはバイナリ互換性のない出力を生成する可能性があります。ただし、C++ コンパイラは、少なくともそれ自体に対してバイナリ互換性があることが保証されています。)ライブラリには、次の 3 つのオプションがあります。

  • 特定の C++ コンパイラとリンカーに一致するバイナリを選択します。

  • コンパイラを使用して、ライブラリ ソースを自分でコンパイルします。また

  • C++ コンパイラとリンカーでもサポートされている特定のバイナリ標準 (DLL ライブラリ形式や Microsoft の COM 標準など) に準拠するライブラリ バイナリを選択します。

結論として、スタック オブジェクトとヒープ オブジェクトに関する質問は意味がありません。C++ には「スタック オブジェクト」のようなものはありません。引数が関数に渡される方法を明示的に制御することはできません。これは、C++ コンパイラがその方法を決定するものであるためです。また、この動作を制御するためのキーワードと特別な構文 (つまり、参照、ポインター、autoandregisterキーワードと同様に)、通常、パラメーターが特定の方法で渡されるという保証はありません。特定のコンパイラをよく知っている場合は、このコンパイラでパラメーターの受け渡しがどのように機能するかを推測できるかもしれません...しかし、一般的には、このメカニズムについて知ることはできません。知る必要はありません。

PS:「スタック オブジェクト」という用語は、パラメーターの受け渡しに関して意味がないだけではないことを忘れていました。さらに一般的に言えば、スタックにオブジェクトを割り当てるようにコンパイラに指示する方法はまったくありません。通常、ローカル変数はスタック割り当てられますが、これが保証されるわけではありません。それが、アセンブリ言語へのエスケープを選択した理由だと思います。その後、明示的にスタックpushpopの間で値をやり取りすることができます (CPU によって管理されます)。

于 2010-08-06T20:40:31.170 に答える
1

あなたが示しているように構造体を設定する必要があると思う理由はわかりませんが、それにもかかわらず、あなたは間違っています。

次のようにする必要があります。

int* pInt = (int*)pMyStruct;   
*pInt++ = 10;   
 float *pFloat = (float*)pInt;   
 *pFloat++ = 2.545;   
 char *pChar = (char*)pFloat;   
 *pChar = 'c';   

これは完全にプラットフォームに依存しており、おそらく正しく動作しないでしょう。

myStruct に値が設定されていると仮定すると、呼び出すための簡単な解決策の 1 つは、次のfooように変更することです。

void foo(MyStruct* pMyStruct);

それが不可能な場合は、スタックにコピーする必要があります。何かのようなもの

 char rawBytes[sizeof(MyStruct)];
 memcpy(&rawBytes,MyStruct,sizeof(MyStruct));
 foo(*(MyStruct*)rawBytes)`

動作する可能性があります。コンパイル時に MyStruct がわからないため、コンパイラはスタック操作コードを生成できません。

実行時に MyStruct の大きさを知っていると思います。したがって、次のようになります。

 _asm{ 
    //pseudo-assembly
    cx = numBytesInMyStruct
    bx = pointerToYourFakeMyStruct
    loop cx
     push *bx++
    call foo
 }
于 2010-08-06T19:47:07.697 に答える