使用 va_list 作为参数从一个地方调用任何函数
Call any functions from one place using va_list as arguments
我有主要更新,我在通话前进行访问控制。我想在我的代码中使用一个地方来调用任何紧急函数。
我有一个结构动作:
{
FUNC_PROTOTYPE pfnAction;
unsigned int argsnum;
va_list argsval;
};
当我需要调用 func 时,我会这样做:
1 将函数和参数放入队列; 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)
但是我的 args 里面的 func 已经损坏了。
我想,当我从队列中弹出时遇到的问题:
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没问题
您不能将可变参数列表作为对象传递,即使使用 va_list
也是如此。那是行不通的/是未定义的行为。
如果您使用 C++ 进行编程,则 (1) 不要使用 C 标记您的问题,并且 (2) 存储带有绑定参数的 std::function
。
正如@mSalters 所说,您不能传递 va_list - 它仅在具有变量 args 的函数的堆栈帧中有效。
在严格传递堆栈的体系结构上,您可能可以通过存储 va_list 指向的初始地址和后面的地址来破解它遍历所有预期的参数,然后将两个地址之间的所有内存复制到分配的缓冲区中。这必须在您排队之前完成。在队列弹出端,您可以通过使 va_list 指向您的副本来伪造 va_arg。
除了实验之外,我不建议出于任何目的实际这样做。
在许多现代架构中,这行不通,因为一些变量也在寄存器中传递。有关 va_arg 的混乱程度的详细信息,请参阅 this article。
我有主要更新,我在通话前进行访问控制。我想在我的代码中使用一个地方来调用任何紧急函数。
我有一个结构动作:
{
FUNC_PROTOTYPE pfnAction;
unsigned int argsnum;
va_list argsval;
};
当我需要调用 func 时,我会这样做:
1 将函数和参数放入队列; 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)
但是我的 args 里面的 func 已经损坏了。
我想,当我从队列中弹出时遇到的问题:
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没问题
您不能将可变参数列表作为对象传递,即使使用 va_list
也是如此。那是行不通的/是未定义的行为。
如果您使用 C++ 进行编程,则 (1) 不要使用 C 标记您的问题,并且 (2) 存储带有绑定参数的 std::function
。
正如@mSalters 所说,您不能传递 va_list - 它仅在具有变量 args 的函数的堆栈帧中有效。
在严格传递堆栈的体系结构上,您可能可以通过存储 va_list 指向的初始地址和后面的地址来破解它遍历所有预期的参数,然后将两个地址之间的所有内存复制到分配的缓冲区中。这必须在您排队之前完成。在队列弹出端,您可以通过使 va_list 指向您的副本来伪造 va_arg。
除了实验之外,我不建议出于任何目的实际这样做。
在许多现代架构中,这行不通,因为一些变量也在寄存器中传递。有关 va_arg 的混乱程度的详细信息,请参阅 this article。