gcc中的运行时参数(反向va_args / varargs)

时间:2014-03-04 10:51:56

标签: c function gcc argument-passing variadic-functions

我正在尝试对我正在研究的微控制器的解释器进行一些改进。为了执行内置函数,我目前有类似的东西(虽然快一点):

function executeBuiltin(functionName, functionArgs) {
  if (functionName=="foo") foo(getIntFromArg(functionArgs[0]));
  if (functionName=="bar") bar(getIntFromArg(functionArgs[0]),getBoolFromArg(functionArgs[1]),getFloatFromArg(functionArgs[2]));
  if (functionName=="baz") baz();
  ...
}

但它适用于资源非常有限的嵌入式设备(ARM),我需要大幅减少代码大小。我想做的是有一个通用函数来调用其他函数不同的参数 - 这样的事情:

function executeBuiltin(functionName, functionArgs) {
  functionData = fast_lookup(functionName);
  call_with_args(functionData.functionPointer, functionData.functionArgumentTypes, functionArgs);
}

所以我希望能够调用一个标准的C函数并将它传递给它需要的任何参数(可能都是不同的类型)。为此,我需要一个call_with_args函数。

我想避免重写每个函数以获取argc + argv。理想情况下,每个被调用的函数都是完全标准的C函数。

有一个discussion about this here - 但自1993年撰写该帖以来,有什么变化吗?特别是当我在ARM上运行时,参数在寄存器而不是堆栈中。即使它不在标准C中,是否有任何GCC具体可以做到?


UPDATE:看来,尽管根据规范行为是“未定义的”,但看起来因为C调用的工作方式,你可以向函数传递更多的参数,而不是预期和一切都会好的,所以你可以将所有参数解压缩到uint32s数组中,然后只需将每个uint32传递给函数。

这使得为调用编写“漂亮”代码变得更加容易,并且它似乎工作得很好(在32位平台上)。唯一的问题似乎是传递64位数字并编译为64位x86,因为在这种情况下似乎做了一些特别奇怪的事情。

3 个答案:

答案 0 :(得分:1)

是否可以在编译时使用宏? 有点像: https://www.redhat.com/archives/libvir-list/2014-March/msg00730.html

如果需要运行时,也许可以利用__buildin_apply_args()。

答案 1 :(得分:0)

来自this document,第5.5节,参数传递,似乎参数在寄存器和堆栈中传递,就像今天的大多数平台一样。

使用“非标准C”我打算打包参数并使用一些asm()调用文档后面的函数。但是你需要一个关于被调用函数的签名的最小信息(我的意思是,每个参数要传递多少位)。

从这个角度来看,我更愿意准备一个函数名数组,一个函数指针数组和一个枚举函数签名数组(每个参数的位数......你不需要区分例如,来自char *的void *和签名上的switch / case,以及最后一个上的switch / case。所以我在这里报告了两个答案。

答案 2 :(得分:0)

您可以执行非常简单的序列化来传递任意参数。为每个传递的参数创建一个数组和memcpy sizeof(arg)字节。

或者您可以为函数参数创建结构。

每个函数都使用char *或void *。然后传递一个指向带有该函数参数的结构的指针,或者定义一组宏或函数来编码和解码数组中的任意数据并将指针传递给该数组。