Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C语言中,给定一个可变参数列表,如何使用它们构建函数调用?_C_Assembly_Ffi_Libffi - Fatal编程技术网

在C语言中,给定一个可变参数列表,如何使用它们构建函数调用?

在C语言中,给定一个可变参数列表,如何使用它们构建函数调用?,c,assembly,ffi,libffi,C,Assembly,Ffi,Libffi,假设有一个以某种方式存储的参数列表,例如在数组中 给定一个函数指针,如何通过存储的参数列表调用它 我不想把数组作为参数传递,ok。你明白了,好吗?我想把它的每个元素作为参数传递。数组只是为了说明,我可以将参数存储在某个元组结构中。另外,请注意,我手头有一个函数指针,可能有一个字符串格式的签名。我并不是要定义一个能够处理变量列表的函数 我知道如何做到这一点的唯一方法是采用汇编(通过\uu asm push等)或以下方法: void(*f)(…); int main() { f=; int-args

假设有一个以某种方式存储的参数列表,例如在数组中

给定一个函数指针,如何通过存储的参数列表调用它

我不想把数组作为参数传递,ok。你明白了,好吗?我想把它的每个元素作为参数传递。数组只是为了说明,我可以将参数存储在某个元组结构中。另外,请注意,我手头有一个函数指针,可能有一个字符串格式的签名。我并不是要定义一个能够处理变量列表的函数

我知道如何做到这一点的唯一方法是采用汇编(通过
\uu asm push
等)或以下方法:

void(*f)(…);
int main()
{
f=;
int-args[];
int num_args=;
开关(num_args)
{
案例0:
f();
打破
案例1:
f(args[0]);
打破
案例2:
f(args[0],args[1]);
打破
/*等*/
}
返回0;
}
我不太喜欢这种方法

有没有另一种可移植的较短形式

有几种脚本语言能够调用C函数

Python或Ruby等脚本语言是如何做到这一点的?他们如何以可移植的方式实现它?他们最终是使用多个平台还是以上平台的组装

看,我并不是在问参数封送的细节以及从脚本语言到C的其他东西,我只感兴趣的是,最终,脚本语言对C函数的调用是如何在内部构建的

编辑 我将保留问题的标题,但我认为更好的提问方式是:

如何调用C函数,其指针和签名仅在运行时可用

更新 发件人:

调出是一种正常的函数调用。在动态环境中, 我们创建一个“调用接口”对象,它指定(二进制) 输入/输出类型;此对象可以与任意 函数指针和输入值数组,用于执行函数调用并检索其结果。这样做需要 操纵堆栈并了解如何调用函数, 这些是libffi处理的细节


感谢@AnttiHaapala的搜索、查找和指点。这正是我所寻找的,它正被许多脚本语言所使用,它是一个可移植的库,跨多个体系结构和编译器实现。

为了安全起见,您应该在发送变量之前将其解压缩。使用汇编程序破解参数堆栈可能无法在编译器之间移植。调用约定可能会有所不同

我不能代表Ruby说话,但我已经使用Perl和Python的C接口编写了很多程序。Perl和Python变量不能与C变量直接比较,它们有更多的特性。例如,Perl标量可能具有双字符串和数字值,在任何时候只有其中一个是有效的


Perl/Python变量和C之间的转换是使用
pack
unpack
完成的(在Python的
struct
模块中)。在C接口上,您必须根据类型调用特定的API来进行转换。因此,它不仅仅是一个直接的指针传输,当然也不涉及汇编程序。

您问过,使用给定数量的参数调用任何函数指针的可移植方式是什么。正确的答案是没有这种方法

例如,python能够通过ctypes模块调用C函数,但这是可移植的,只要您知道确切的原型和调用约定。在C语言中,实现这一点的最简单方法是在编译时知道函数指针的原型

更新 对于python/ctypes示例,在每个启用了ctypes模块的平台上,python都知道如何为给定的参数集编写调用堆栈。例如,在Windows上,python知道两种标准的调用约定——堆栈上参数的C顺序的cdecl和带有“pascal样式顺序”的stdcall。在Linux上,它确实需要考虑是调用32位还是64位共享对象,等等。如果python被编译到另一个平台,那么CType也需要更改;ctypes模块中的C代码本身是不可移植的

更新2 对于Python来说,魔法就在这里:。值得注意的是,它似乎将你所需要的东西联系起来。

@AnttiHaapala指出。以下是关于它的一些信息:

什么是Liffi? 有些程序在编译时可能不知道要传递给函数的参数。例如,可以在运行时告诉解释器用于调用给定函数的参数的数量和类型libffi’可用于此类程序中,以提供从解释器程序到编译代码的桥梁

“libffi”库为各种调用约定提供了一个可移植的高级编程接口。这允许程序员在运行时调用调用接口描述指定的任何函数

FFI代表外部功能接口。外部函数接口是接口的流行名称,它允许用一种语言编写的代码调用用另一种语言编写的代码。“libffi”库实际上只提供功能齐全的外部函数接口中最低的、依赖于机器的层。“libffi”上方必须存在一个层,该层处理两种语言之间传递的值的类型转换

“libffi”假设您有一个指向要调用的函数的指针,并且您知道要传递它的参数的数量和类型,以及函数的返回类型


历史背景 libffi最初由Anthony Green(SO用户:)开发,其灵感来源于Silicon Graphics的Gencall库。Gencall由Gianni Mariani开发
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;
}
#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;
}