使用va_list作为参数从一个地方调用任何函数

时间:2015-10-19 20:12:51

标签: c variadic-functions

我有主要更新,我在呼叫前进行访问控制。我想在我的代码中使用一个地方来调用任何紧急功能。

我有一个结构ACTION:

{
    FUNC_PROTOTYPE pfnAction;
    unsigned int   argsnum;
    va_list        argsval;
};

当我需要调用func时,我会这样做:
1 将func和参数放入队列; 2 在下次更新时弹出它们

{
    ACTION action;

    while(!Queue_isEmpty())
    {   // check and pop urgent functions
        if(Queue_Pop(&action))
        {
            action.pfnAction(action.argsnum, action.args);
            va_end(action.args);
        }
    }
}

例如,我尝试拨打

void func(unsigned int argsnum, va_list args)

但我在func中的 args 已损坏。

我想,当我从队列中弹出时出现了这个问题:

Queue_Pop(P_ACTION p_res)
{
    if(!Queue_isEmpty())
    {
       p_res->pfnAction = header->pfnAction;
       p_res->argsnum = header->argsnum;

       if(0 < p_res->argsnum)
       {
           p_res->argsval = header->argsval;
           va_end(header->argsval);
       }
       ...
    }
}

action.args没问题。

2 个答案:

答案 0 :(得分:0)

您不能将vararg列表作为对象传递,甚至不能使用va_list。这不起作用/是未定义的行为。

如果您正在使用C ++进行编程,那么(1)不要用C标记您的问题,并且(2)存储带有绑定参数的std::function

答案 1 :(得分:0)

正如@mSalters所说,你不能传递va_list - 它只在具有变量args的函数的堆栈帧中有效。

在严格传递堆栈的架构上,可能能够通过存储va_list指向的初始地址和遍历所有预期参数后的地址来破解它,然后复制所有两个地址之间的内存进入分配的缓冲区。这必须在排队之前完成。在队列弹出方面,你可以通过使va_list指向你的副本来伪造va_arg。

我不建议将此实际用于除实验之外的任何其他目的。

在许多现代架构中,这不起作用,因为一些变量也在寄存器中传递。有关va_args如何混乱的详细信息,请参阅this article