从Fortran传递标量和任意维度的数组到C

4
我有如下Fortran子程序,名为show_value,该子程序调用了名为show_value的C函数:
INTERFACE
    SUBROUTINE show_value(variable) BIND(C, name = "show_value")
        USE, INTRINSIC :: iso_c_binding
        TYPE(*) :: variable
    END SUBROUTINE
END INTERFACE

函数show_value的作用:

void show_value(const void *variable)
{
    printf("%d\n", *(int *) variable);
}

当向Fortran子程序传递标量时,它的工作效果很好。例如:

INTEGER :: x
x = 12
call show_value(x)

这会调用C函数show_value并打印12,这是正确的。
根据Fortran文档,如果想要启用子例程show_value接收数组(任意维度)而不仅仅是标量,则应将TYPE(*) :: variable更改为TYPE(*), DIMENSION(..) :: variable
在进行了这些更改后,执行以下Fortran代码:
INTEGER, DIMENSION(3) :: y
y(1) = 15
y(2) = 17
y(3) = 19
call show_value(y)

show_value函数不再打印正确的信息(即打印随机数)。此外,我发现C函数接收到的地址比原始地址(在Fortran中)低528。为了确认这一点:

void show_value(const void *variable)
{
    printf("%d\n", *(int *) (variable + 528));
}

这段代码输出 15 (正确的数字)。你有什么想法吗?

环境:Ubuntu 14.04 64 位,gfortran 4.9。


修复了,感谢指出! - user7698505
1个回答

3
尽管您的第一个案例使用标量参数与void*参数匹配,但当调用参数为假定秩(表示为type(*), dimension(..) :: variable)时,Fortran过程与具有相应形式参数const void *variable的C过程不可互操作。因此,必须使用CFI_cdesc_t机制:
#include <stdio.h>
#include <ISO_Fortran_binding.h>

void show_value(const CFI_cdesc_t* variable)
{
  printf("%d\n", *(int*) variable->base_addr);
}

您可以在Fortran 2018 18.5.3中找到详细信息。
本质上,这是一个描述符,其中包含大部分Fortran实体的详细信息。在这里,base_addr是数据的起始位置,但您还将找到可分配/指针/数据状态、秩、范围和类型。
不幸的是,gfortran 4.9不支持此功能。如果有支持的话,那么只会在最近的版本中支持。
或者,您可以避免使用假定秩假定类型的实际参数,而是传递参数的C地址,使用c_loc。虽然不太优雅,但更广泛地受到支持。
use, intrinsic :: iso_c_binding, only : c_loc, c_ptr, c_int
interface
  subroutine show_value(variable) bind(c)
    import c_ptr
    type(c_ptr), value :: variable
  end subroutine
end interface

integer(c_int), target :: x, y(3)

x = 12
y = [15, 17, 19]

call show_value(c_loc(x))
call show_value(c_loc(y))

end

然而,这也带来了一个问题,即C函数如何知道如何处理参数。


谢谢您的反馈。您能否举个例子使用 c_loc?那太好了! - user7698505
当然,你可以选择(不可移植的)尝试理解gfortran传递的数组描述符(在这种情况下是前528个字节)。即使我能帮忙,我也强烈建议不要这样做。 - francescalus
请查看此链接以获取有关gfortran中此功能状态的更多信息:https://gcc.gnu.org/onlinedocs/gfortran/Further-Interoperability-of-Fortran-with-C.html。另外,如果您想深入了解gfortran数组描述符,请参阅此链接:https://thinkingeek.com/2017/01/14/gfortran-array-descriptor/。 - Rodrigo Rodrigues

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接