Вызов функции, принимающей объект стека в качестве аргумента с данными на основе кучи - PullRequest
0 голосов
/ 06 августа 2010

У меня сложная проблема, которую нужно решить, потому что я застрял и не нашел способа ее решить. Вот код

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, как показано выше.

Теперь, как я могу преобразовать указатель кучи пустоты в объект типа стека. Каким-то образом, если я получу адрес аргумента a_myStruct, равный foo, я могу указать void* на это место, но, опять же, я не могу разыменовать void*, чтобы он был преобразован в объект типа MyStruct .

Есть ли другой способ решить проблему? Как и в C ++, мы можем определить тип во время выполнения.


У меня проблема с вызовом функций во время выполнения в C ++, которые могут иметь сигнатуру с полными пользовательскими типами, которые неизвестны во время компиляции. Но детали этих типов мне доступны (поскольку я расшифровал детали определенного типа) из библиотеки типов или из DIA SDK). Но главная проблема в том, что теперь я хочу вызывать эти функции во время выполнения. Во время компиляции у меня просто есть адрес функции и детали определенного пользователем типа, какой объект или указатель участвует в качестве аргумента этой сигнатуры функции. Теперь, если я хочу вызвать эту функцию во время выполнения, мне нужно сначала заполнить этот тип во время выполнения, создав временный блок в куче и заполнив этот блок данными. У меня есть все детали этого типа.

Теперь проблема в том, что я не знаю, что функция принимает аргумент в качестве указателя того типа, о котором у меня есть доступные данные, или этот аргумент является точно стековым объектом этого типа. Если у меня есть указатель на этот тип, нет проблем, но если есть объект, у меня есть большая проблема, чтобы вызвать эту функцию во время выполнения.

Ответы [ 2 ]

1 голос
/ 07 августа 2010

Я должен признать, что даже с учетом предоставленной вами дополнительной информации, я не до конца понимаю ваш вопрос.Но позвольте мне сказать что-то общее о стеке и куче и C ++:

То, как аргумент передается функции, - это деталь реализации конкретного компилятора C ++т.е.это может варьироваться от одного компилятора C ++ к другому.Метод, посредством которого аргументы передаются в функции, называется соглашением о вызовах .Некоторые компиляторы не используют ни стек, ни кучу для передачи аргументов;вместо этого они используют регистры процессора, если это возможно.(Компилятор Watcom C ++ является / был выдающимся примером компилятора, который предпочитает регистры для передачи аргументов функции.)

Это означает, что любой компилятор C ++ может создавать двоичные файлы, которые не являются binary-совместим с другим компилятором C ++.(Стандарт языка C ++ не предписывает двоичный стандарт для скомпилированного вывода, поэтому разные компиляторы могут выдавать двоично-несовместимый вывод; но любой компилятор C ++ гарантированно будет двоично-совместимым, по крайней мере, сам с собой.) Таким образом, если вы хотите использоватьбиблиотека, у вас есть три варианта:

  • выберите двоичный файл, который соответствует вашему конкретному компилятору и компоновщику C ++;

  • скомпилируйте исходные коды библиотеки самостоятельно, используяваш компилятор;или

  • выберите двоичный файл библиотеки, который соответствует определенному двоичному стандарту (например, формат библиотеки DLL или стандарт COM Microsoft), который также поддерживается вашим компилятором и компоновщиком C ++.

В заключение, ваш вопрос об объекте стека и объекте кучи не имеет смысла .В C ++ не существует такого понятия, как «объект стека».У вас нет явного контроля над тем, как аргумент передается функции, потому что это то, что компилятор C ++ сам решит, как это делать, и, хотя, кажется, существуют ключевые слова и специальный синтаксис для управления этим поведением (а именно ссылки, указатели,как и ключевые слова auto и register, они , как правило, не дают вам никакой гарантии, что параметр будет передан определенным образом.Если вы хорошо знаете один конкретный компилятор, то вы сможете определить, как передача параметров работает с этим компилятором ... но обычно , вы не можете - и не должны - знатьоб этом механизме.

PS: Я забыл упомянуть, что термин "стековый объект" не просто бессмысленен с точки зрения передачи параметров.Более того, просто нет способа сказать компилятору разместить объект в стеке.Хотя локальные переменные обычно будут размещаться в стеке, никакой гарантии для этого нет.Я полагаю, именно поэтому вы решили уйти на ассемблере.Затем вы можете явно push и pop значения в / из стека (как управляется ЦП).

1 голос
/ 06 августа 2010

Я не понимаю, почему вы думаете, что вам нужно заполнить свою структуру так, как вы показываете, но независимо от того, что вы делаете это неправильно.

Это должно быть больше похоже на:

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

Это полностью зависит от платформы и, вероятно, не будет работать правильно.

Если вы заполнили myStruct, одним из простых решений для вызова 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
 }
...