【问题标题】:c++: call a function with with various number of arguments stored in an array?c ++:调用一个函数,其中存储在数组中的参数数量不同?
【发布时间】:2011-12-26 19:57:45
【问题描述】:

我有一个带有签名double func(double,...) 的函数,我确信我传递给 func 的所有参数都是双精度类型。所有参数都存储在一个称为参数的向量中,我只是想知道是否有办法编写通用代码将argumentVector中指定的任意数量的参数传递给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;

【问题讨论】:

  • 你能修改func()吗?还是你不得不在调用方做所有事情?
  • 我可以创建一个测试函数(就像我已经做过的那样),但最后我正在尝试使用一些库,所以我被困在客户端!
  • 如果您可以访问可变参数模板,则可以通过参数包中的递归和参数准备来做到这一点。只是一个想法,因为我现在没有时间把它写成一个完整的答案。
  • 可以肯定的是,使用 g++ -S -l 编译它,这样您就可以向我们展示在该函数调用中生成的程序集的其余部分,看看它是否有任何区别。
  • @ManuelFerreria 我正在使用 VC,但我已经发布了编译器生成的汇编代码

标签: c++ assembly argument-passing


【解决方案1】:

以下在 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;
}

【讨论】:

  • 迄今为止最好的答案,但是在我将它复制到我的代码中后它无法正常运行,第一件让事情变得有点混乱的是move ebp,esp,另一个在程序结束时,我只是改变了他们的立场。现在只有两个参数之一被传递
  • 我想帮你解决这个问题,但我不明白为什么move ebp,esp 会阻止代码正常运行......另外,当你“改变他们的位置”时你到底做了什么“? (P.S. asm 代码中有一些小错误,现在修复它。)
  • 我终于让你的代码为我工作了!我已经编辑了您的答案以添加我的所有更改!但无论如何感谢您的帮助。如果我在不知不觉中做错了什么,请告诉我!我不知道任何程序集,只是使用 VC 调试器,我已经达到了那个代码!
  • 我很高兴它现在对你有用。你用一个新变量(temp)替换了ebp,我认为你可以通过使用esi来避免这种情况。我将以这种方式编辑代码并包含您对返回值的修改。如果这对您的编译器不起作用,请报告。
【解决方案2】:

根据我的具体要求,我会做你在下面看到的这两个中的一个。使用 Assembly 将是我的选项列表中的最后一个。

同上。 1 如果你所有的参数都是相同的类型,为什么不直接传递向量呢?它是类型安全的,并且不会像使用可变长度参数列表时那样溢出。请记住,如果您只希望函数使用向量的一部分,也可以传递开始和结束迭代器。

同上。 2 如果您的论点属于不同类型,请使用Boost.Any

【讨论】:

  • none 这些是我的选择,因为我试图将它用于一些预定义的功能。我可以确保我传递了正确数量的参数,并且我知道所有参数都是双精度类型。但我可能会用不同数量的参数调用这个函数!
【解决方案3】:

您是否以正确的颠倒顺序推送值?

如果你有 void func(int a, int b, int c)

你必须做的:

push c
push b
push a
call func
add esp, 4*3

如果您只是想嵌入程序集,并完全按照您放置的方式执行:

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;")

但在这样做之前,请确保它确实是一种优化,而不是过早的优化。

【讨论】:

  • 问题是当我在 for 中使用汇编代码时代码中断。顺便说一下,数字的顺序没有区别,到目前为止,我只是试图将它们全部相乘(稍后我会更正它)
猜你喜欢
  • 1970-01-01
  • 2021-12-18
  • 2019-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多