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
我无法对此进行明显的测试,但在这一点上它在语法上是正确的并且根据我对你的问题陈述的阅读具有正确的间接级别。
我有一个要与 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
我无法对此进行明显的测试,但在这一点上它在语法上是正确的并且根据我对你的问题陈述的阅读具有正确的间接级别。