Fortran 与 C 指针结构的互操作性

Fortran interoperability with C pointer struct

我有一个要与 Fortran 一起使用的商业 C 库。有两个函数和一个指针结构,如:

struct env;
typedef struct env *ENVptr;

两个函数都有原型:

ENVptr open(int *status_p);
int close(ENVptr **env_p);

我写了一个 Fortran 界面来访问它们:

interface
    function c_open(status) bind(c, name='c_open')
        use, intrinsic :: iso_c_binding
        integer(kind = c_int) :: status
        type(c_ptr) :: c_open
    end function 

    function c_close(env) bind(c, name='c_close')
        use, intrinsic :: iso_c_binding
        type(c_ptr)                  :: env
        integer(kind = c_int)        :: c_close
    end function
end interface

我在我的 Fortran 程序中使用此代码:

type(c_ptr)  :: env = c_null_ptr

env = c_open(status)

if ( status .ne. 0 ) then
   print *, 'Could not open environment'
   stop
end if

...some more code...

if ( c_associated(env) ) then
   status = c_close(env)
    if ( status .ne. 0 ) then
       print *, 'Could not close environment.'
    end if
end if

但是当我执行程序时,程序到达 c_close 函数时出现分段错误。

这是连接 C 例程的正确方法吗?

我看不出您的程序如何链接,因为过程的绑定名称必须与实际 C 原型中的名称一致。我想您可以使用 *.def 文件将名称对齐。 Fortran 也有参数关键字的概念,因此在我看来,使接口中的 Fortran 虚拟参数与其记录的参数名称一致是一种很好的做法。除此之外,您的界面主体中似乎具有正确的间接级别,所以我的版本是:

interface
   function c_open(status_p) bind(C,name='open')
      use, intrinsic :: iso_c_binding
      implicit none
      type(c_ptr) :: c_open
      integer(kind = c_int) status_p
   end function c_open

   function c_close(env_p) bind(c,name='close')
      use, intrinsic :: iso_c_binding
      implicit none
      integer(c_int) c_close
      type(c_ptr) env_p
   end function c_close
end interface

现在,调用 c_close 时存在间接级别问题,因为 ENVptr 的 C typedef 已经使它成为指针,因此 ENVptr** envp 是指向指向指针的指针。在您的 Fortran 代码中,您传递的 c_ptr 通过引用指向不透明类型,因此您传递的是指向指针的指针。因此,您需要创建一个额外的间接级别以使其运行。因此,我会尝试将您的代码修改为:

type(c_ptr)  :: env = c_null_ptr, envpp = c_null_ptr
target env
integer(c_int) status

env = c_open(status)

if ( status .ne. 0 ) then
   print *, 'Could not open environment'
   stop
end if

!...some more code...

if ( c_associated(env) ) then
   envpp = c_loc(env)
   status = c_close(envpp)
    if ( status .ne. 0 ) then
       print *, 'Could not close environment.'
    end if
end if

我无法对此进行明显的测试,但在这一点上它在语法上是正确的并且根据我对你的问题陈述的阅读具有正确的间接级别。