假设有某种方式存储,例如数组中的参数列表。
给定一个函数指针 ,我怎么能让它传递的参数的存储列表中的电话吗?
我并不想通过数组作为确定参数。 你猜对了,好吗? 我想它的每个元素作为参数传递。 阵列仅仅是为了说明,我可以存储在一些元组结构的参数。 另外,看我手边有一个函数指针,并可能在字符串格式的签名 。 我并不想只是定义一个函数,它能够对付可变参数列表。
我看到如何做到这一点的唯一方法是通过采用组件(由__asm push
等),或者这样的:
void (*f)(...);
int main()
{
f = <some function pointer>;
int args[]; <stored in a array, just to illustrate>
int num_args = <some value>;
switch(num_args)
{
case 0:
f();
break;
case 1:
f(args[0]);
break;
case 2:
f(args[0], args[1]);
break;
/* etc */
}
return 0;
}
我不喜欢这种方法太多...
难道还有其他的便携和更短的形式?
一些脚本语言都能够调用C函数。
如何脚本语言如Python或Ruby这样做呢? 他们是如何实现它在便携方式? 难道他们只是使用汇编于多个平台或末期的?
你看,我真的不问从脚本语言到C参数编组和其他东西的细节,我感兴趣的只是如何,到底,在内部,由脚本语言调用C函数建立。
编辑
我会保持这个问题的标题,但我认为更好的方式询问是:
如何调用其指针,只有在运行时可用签名的C函数?
UPDATE
从对PLT的计划外部接口 :
呼出是一个普通的函数调用。 在动态设置,我们创建了一个“呼叫接口”对象它确定音响ES(二进制)的输入/输出类型; 这个对象可以用一个任意的函数指针和输入值的阵列被用来执行一个标注的功能和检索其结果。 这样做需要操纵堆栈和了解函数是如何被调用,这些都是细节,libffi涉及。
感谢@AnttiHaapala搜索,发现和指出libffi 。 这就是我一直在寻找,它正在使用由一群脚本语言,它是一种便携式库,在多个架构和编译器来实现。
你问什么是调用与参数给定数量的任何函数指针的移动方式。 正确的答案是 , 有没有这样的方法 。
例如蟒蛇是能够通过ctypes的模块调用C函数,但是这只是便携只要你知道确切的原型和调用约定。 在C来实现相同的最简单的方法是了解函数指针在编译时的原型。
更新
对于Python / ctypes的示例中,启用了ctypes的模块每个平台上,Python知道如何编写调用堆栈一组给定的参数。 在Windows例如,Python的2个标准调用约定知道 - 有对栈参数Ç秩序的cdecl,并以“帕斯卡风格排序” STDCALL。 在Linux上它确实需要担心是否调用32个或64位共享对象,等等。 如果蟒蛇被编译到另一个平台,ctypes的需求的变化,以及; 在ctypes的模块C代码不是,因此,便于携带。
更新2
对于Python神奇的是在这里: ctypes的源代码 。 值得注意的是,似乎链接http://sourceware.org/libffi/这可能是你所需要的。
@AnttiHaapala指出libffi 。 下面是一些关于它的信息:
什么是libffi?
某些程序可能不知道在编译的时候什么样的参数将被传递给函数。 举例来说,一个解释可能会在运行时对数量和类型的用于调用特定函数的参数被告知。 “libffi”可以以这样的程序被用于提供从解释程序来编译的代码的桥梁。
该“libffi”库提供一个便携式,高层次的编程接口,以不同的调用约定。 这允许程序员调用由在运行时调用接口描述中指定的任何功能。
FFI代表外国功能界面。 外国功能界面是容许一种语言编写调用其他语言编写的代码代码接口的俗称。 该“libffi”图书馆真的只提供了一个功能齐全的外部函数接口的最低,机器相关层。 阿层必须存在上述“libffi”,处理键入两种语言之间传递的值的转换。
“libffi”假设你有一个指向你想打电话,你知道该函数的数量和类型的参数传递,以及函数的返回类型。
历史背景
libffi,最初是由安东尼·格林(SO用户:开发安东尼绿色 ),是由Silicon Graphics公司的Gencall库的启发。 Gencall由詹尼·马里亚尼开发,然后由SGI所采用,允许通过地址调用的功能,创造了特定调用约定的调用框架的目的。 安东尼绿色精的理念,并将其扩展到其他架构和调用约定和开源libffi。
调用带有libffi战俘
#include <stdio.h>
#include <math.h>
#include <ffi.h>
int main()
{
ffi_cif call_interface;
ffi_type *ret_type;
ffi_type *arg_types[2];
/* pow signature */
ret_type = &ffi_type_double;
arg_types[0] = &ffi_type_double;
arg_types[1] = &ffi_type_double;
/* prepare pow function call interface */
if (ffi_prep_cif(&call_interface, FFI_DEFAULT_ABI, 2, ret_type, arg_types) == FFI_OK)
{
void *arg_values[2];
double x, y, z;
/* z stores the return */
z = 0;
/* arg_values elements point to actual arguments */
arg_values[0] = &x;
arg_values[1] = &y;
x = 2;
y = 3;
/* call pow */
ffi_call(&call_interface, FFI_FN(pow), &z, arg_values);
/* 2^3=8 */
printf("%.0f^%.0f=%.0f\n", x, y, z);
}
return 0;
}
我想我可以断言libffi是做不存在这样一个可移植的方式我问,违背安蒂·哈帕拉的说法。 如果我们不能称之为libffi便携技术,赋予它多远移植/跨编译器和架构中实现,并且接口C标准的规定,我们也不能调用C,或任何东西,便于携带。
信息和历史摘自:
https://github.com/atgreen/libffi/blob/master/doc/libffi.info
http://en.wikipedia.org/wiki/Libffi
为了安全,你应该解开变量在发送之前。 使用汇编破解参数堆栈可能无法编译器之间移植。 调用约定可能会有所不同。
我不能对Ruby说话,但我已经写了使用C接口,Perl和Python相当多的程序。 Perl和Python变量不与C变量直接comparible,他们有很多更多的功能。 举例来说,一个Perl标量可能有双串和数值,其中只有一个是在任何一个时间有效。
的Perl / Python的变量和C之间的转换是利用完成pack
和unpack
(中struct
在Python模块)。 在C接口你必须调用特定的API来进行转换,根据类型。 因此,它不只是一个直指针传递,它当然不涉及汇编。
文章来源: In C, given a variable list of arguments, how to build a function call using them?