0

当函数返回其值时,似乎从 libffi 返回 double 数据类型的函数未正确转换,这是我使用的代码:

#include <stdio.h>
#include <stdlib.h>
#include <ffi.h>
#include <math.h>  // The make call the function `cos` by the FFI.

int main()
{
  ffi_cif cif;
  ffi_type *args[1];
  void *values[1];
  ffi_arg rc;

  args[0] = &ffi_type_double;

  void *ptr = malloc(sizeof(double));
  *((double *)ptr) = 3.0;
  values[0] = ptr;

  if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_double, args) == FFI_OK)
      ffi_call(&cif, cos, &rc, values);

  printf("%f\n", (double)rc);

  return 0;
}

结果如下:13830464316077631000.000000

ffi_arg类型是 的别名unsigned long long。文档说明ffi_arg传递给ffi_call函数的类型参数,如果它小于 ,则用于存储数据sizeof(ffi_arg),否则它是指向内存中数据的指针:

sizeof(ffi_arg)对于非浮点类型,右值必须指向大于或等于的存储。对于较小的返回值类型, 必须使用ffi_argor整数类型来保存返回值。ffi_sarg

( https://manpages.debian.org/testing/libffi-dev/ffi_call.3.en.html )

所以我用指针取消引用尝试了它:

void* rc;
// The code to call the function and initialize the CIF...
double my_value = *(double *)((void *)rc);

这使程序崩溃了。

我应该如何访问使用rc变量存储的值?

编辑 1

用于编译程序的命令行:

gcc source.c -lffi -o source

编译时没有错误或警告。

编辑 2

添加 `-Wall' 构建选项后,我得到:

warning: passing argument 2 of 'ffi_call' from incompatible pointer type [-Wincompatible-pointer-types]
ffi_call(&cif, cos, &rc, values);
               ^~~

这个警告似乎在libffi 示例中被忽略了。给出的示例对我来说非常有效(带有此警告)。

4

2 回答 2

3

问题很简单。这ffi_arg不是您应该将返回值放入的类型。相反,第三个参数被定义为一个指向 void的指针,它应该指向一个适当大的对象以包含返回值,并且具有适当的对齐方式和适当的类型,或者被解释为这样的对象,因此:

double rv;
...
ffi_call(&cif, cos, &rv, values);

或者

void *rv = malloc(sizeof (double));
...
ffi_call(&cif, cos, rv, values);
double value = *(double *)rv;

至于警告,这是因为 libffi 代码不是严格可移植的。函数指针不能自动转换为void *. 您可以使用显式强制转换使警告静音:

ffi_call(&cif, (void *)cos, rv, values);

至少它不会使它比现在更错误。

于 2020-05-03T17:23:59.047 回答
1

编辑 - 根据文档

FFI - 对于非浮点类型,右值必须指向 sizeof(ffi_arg) 或更大的存储。对于较小的返回值类型,必须使用 ffi_arg 或 ffi_sarg 整数类型来保存返回值。

ffi_call 的函数定义是

void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);

而不是将 ffi_arg 传递给函数,您需要传递一个分配了双精度空间的 void*。

void* rc = malloc(sizeof(double));
ffi_call(&cif, cos, rc, values);
printf("%f\n", *(double *)rc);

这将导致正确的答案,而无需您对被调用的函数做出任何假设。

于 2020-05-03T16:48:15.227 回答