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++ 编译器都保证至少与它自己是二进制兼容的。)因此,如果你想使用图书馆,你有三个选择:

  • 选择与您的特定 C++ 编译器和链接器匹配的二进制文件;

  • 使用您的编译器自己编译库源;或者

  • 选择符合特定二进制标准(例如 DLL 库格式或 Microsoft 的 COM 标准)的库二进制文件,C++ 编译器和链接器也支持该标准。

总之,您关于堆栈对象与堆对象的问题没有意义。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,一个简单的调用解决方案是foo将其更改为 this:to

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 回答