c ++: вызвать функцию с различным количеством аргументов, хранящихся в массиве? - PullRequest
0 голосов
/ 26 декабря 2011

У меня есть функция с подписью double func(double,...), и я уверен, что все аргументы, которые я передаю func, имеют тип double. Все аргументы хранятся в каком-то векторе, называемом аргументами, мне просто интересно, есть ли способ написать универсальный код для передачи любого количества аргументов, указанных в argumentsVector, в func?

что-то вроде:

for (int i=0;i<agumentVector.size();i++)
    pushstack(argumentVector[i]);
res = call(func);

До сих пор я пробовал этот код, но, похоже, есть проблемы:

double* param = &argumentVector[0];

for(int i=0;i<argumentVector.size();i++)
{
    _asm  sub         esp,8;
    _asm  fld         param;
    _asm  fstp        qword ptr [esp];
    param++;

}
_asm  call        func;
_asm  add         esp,10h;
_asm  fstp        qword ptr res;

- просто сумасшедший результат я получаю! этот код работает без проблем:

double x[2] = {5,6};
double *param = x;
double res;

    _asm  sub         esp,8;
    _asm  fld         x;
    _asm  fstp        qword ptr [esp];
    _asm  sub         esp,8;
    _asm  fld         x+8;
    _asm  fstp        qword ptr [esp];
    param++;
_asm  call        p;
_asm  add         esp,10h;
_asm  fstp        qword ptr res;

cout << res << "\n";

пока аргументы не передаются должным образом!

double x[2] = {5,6};
double *param = x;
double res;

    _asm  sub         esp,8;
    _asm  fld         param;
    _asm  fstp        qword ptr [esp];
    _asm  sub         esp,8;
    _asm  fld         param+8;
    _asm  fstp        qword ptr [esp];
    param++;
_asm  call        p;
_asm  add         esp,10h;
_asm  fstp        qword ptr res;

cout << res << "\n";

Вы понимаете, почему? Хотя x и param были простыми массивами!

- edit2 -

вот полный код сборки, который до сих пор генерировался VC

    double x[2] = {5,6};
010E1A05  fld         qword ptr [__real@4014000000000000 (10EB928h)]  
010E1A0B  fstp        qword ptr [ebp-48h]  
010E1A0E  fld         qword ptr [__real@4018000000000000 (10EB878h)]  
010E1A14  fstp        qword ptr [ebp-40h]  
    double *param = x;
010E1A17  lea         eax,[ebp-48h]  
010E1A1A  mov         dword ptr [ebp-54h],eax  
    double res;
    p(param[0],param[1]);
010E1A1D  mov         esi,esp  
010E1A1F  mov         eax,dword ptr [ebp-54h]  
010E1A22  sub         esp,8  
010E1A25  fld         qword ptr [eax+8]  
010E1A28  fstp        qword ptr [esp]  
010E1A2B  mov         ecx,dword ptr [ebp-54h]  
010E1A2E  sub         esp,8  
010E1A31  fld         qword ptr [ecx]  
010E1A33  fstp        qword ptr [esp]  
010E1A36  call        dword ptr [ebp-14h]  
010E1A39  fstp        st(0)  
010E1A3B  add         esp,10h  
010E1A3E  cmp         esi,esp  
010E1A40  call        @ILT+795(__RTC_CheckEsp) (10E1320h)  

    {
        _asm  sub         esp,8;
010E1A45  sub         esp,8  
        _asm  fld         param+8;
010E1A48  fld         dword ptr [ebp-4Ch]  
        _asm  fstp        qword ptr [esp];
010E1A4B  fstp        qword ptr [esp]  

        _asm  sub         esp,8;
010E1A4E  sub         esp,8  
        _asm  fld         param;
010E1A51  fld         dword ptr [ebp-54h]  
        _asm  fstp        qword ptr [esp];
010E1A54  fstp        qword ptr [esp]  

    }
    _asm  call        p;
010E1A57  call        dword ptr [ebp-14h]  
    _asm  add         esp,10h;
010E1A5A  add         esp,10h  
    _asm  fstp        qword ptr res;
010E1A5D  fstp        qword ptr [ebp-64h]  

    cout << res << "\n";
010E1A60  push        offset string "\n" (10EB834h)  
010E1A65  mov         esi,esp  
010E1A67  sub         esp,8  
010E1A6A  fld         qword ptr [ebp-64h]  
010E1A6D  fstp        qword ptr [esp]  
010E1A70  mov         ecx,dword ptr [__imp_std::cout (10EF3A8h)]  
010E1A76  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10EF3ACh)]  
010E1A7C  cmp         esi,esp  
010E1A7E  call        @ILT+795(__RTC_CheckEsp) (10E1320h)  
010E1A83  push        eax  
010E1A84  call        std::operator<<<std::char_traits<char> > (10E1294h)  
010E1A89  add         esp,8  
    return 0;

Ответы [ 3 ]

1 голос
/ 27 декабря 2011

Следующее работает в Visual Studio, но я думаю, что вы можете легко исправить встроенный синтаксис ассемблера, чтобы он соответствовал требованиям вашего компилятора.

double variadicDoubleFunc(double, ...)
{
}

double callVariadicDoubleFunc(double * doubles, unsigned int numDoubles)
{
    // sizeof(double) must be 8!
    if (numDoubles == 0)
        return 0.0;
    double * lastDouble = doubles + (numDoubles - 1);
    double result = 0.0;

    __asm mov eax, numDoubles
    __asm mov edx, lastDouble
    __asm push esi
    __asm mov esi, esp
    __asm and esp, 0xFFFFFFC0

    __asm label_loop:
    __asm sub esp, 8
    __asm fld qword ptr [edx]
    __asm fstp qword ptr [esp]
    __asm sub edx, 8
    __asm sub eax, 1
    __asm test eax, eax
    __asm jnz label_loop

    __asm call variadicDoubleFunc
    __asm fstp qword ptr result
    __asm mov esp, esi
    __asm pop esi

    return result;
}
0 голосов
/ 27 декабря 2011

В зависимости от моих конкретных требований, я бы выполнил одно из двух, которые вы увидите ниже.Использование Assembly будет последним в моем списке опций.

Op.1 Если все ваши аргументы имеют одинаковый тип, почему бы просто не передать вектор?Это безопасный тип, и вы не можете переполниться, как при использовании списков аргументов переменной длины.Помните, что вы можете также передать начальный и конечный итераторы, если хотите, чтобы функция использовала только часть вектора.

Op.2 Если ваши аргументы имеют разные типы, используйте Boost.Any .

0 голосов
/ 27 декабря 2011

Вы нажимаете значения в правильном порядке в обратном порядке ?

Если у вас есть void func(int a, int b, int c)

, вам нужно сделать:1010 * Если вы просто хотите встроить сборку и выполнить ее в точности так, как вы ее разместили:

for(int i=0;i<argumentVector.size();i++)
{
    parm++;
    __asm__ __volatile__ ( 
                      "sub         esp,8;"
                      "fld         parm;"
                      "fstp        qword ptr [esp]")

}
__asm__ __volatile__ ( "call        func;"
                       "add         esp,10h;"
                       "fstp        qword ptr res;")

Но прежде чем делать это, убедитесь, что это действительно оптимизация, а не преждевременная.

...