无法从 Fortran 90 中返回的 C 浮点指针获取数据
Posted
技术标签:
【中文标题】无法从 Fortran 90 中返回的 C 浮点指针获取数据【英文标题】:Cannot get data from a returned C float pointer in Fortran 90 【发布时间】:2013-03-12 19:40:01 【问题描述】:我正在从 Fortran 90 程序调用 C 函数(我必须使用 Fortran 90)。这个 C 函数接受几个参数并返回一个浮点指针。我似乎无法在 Fortran 代码中正确打印返回的数据。它只是显示一个非常大的数字(我假设它是指针的地址。)
我已经成功地将 REAL Fortran 变量作为参数传递,让 C 函数设置它们(因为 Fortran 通过引用传递)并随后访问数据。但是,我必须将指针作为返回变量返回,因为这是旧函数使用的方法(我正在重新实现。)
在 Fortran 90 中有没有办法从 C 函数返回的非字符(实数、整数等)指针访问数据? (请注意:我不能使用 ISO C 绑定,因为这仅适用于 Fortran 2003 及更高版本。)我已经在下面说明了我想要做什么......
谢谢!
Fortran 程序
program test_real
real, dimension(10) :: realpt
integer nbr
integer i
real :: a=1.0
real :: b=2.0
real :: c=3.0
nbr = 9
realpt = getpointer(a, b, c)
do 10 i = 1, nbr
print *,"return: ",realpt(i)
10 continue
stop
End
C 函数
float* getpointer(float *a, float *b, float *c)
float *rfl = (float *) calloc(9,sizeof(float));
int i=0;
for(i=0;i<3;i++)
rfl[i] = *a;
for(i=3;i<6;i++)
rfl[i] = *b;
for(i=6;i<9;i++)
rfl[i] = *c;
return(rfl);
// End of getpointer function
输出
return: 3.1661344E+07
return: 3.1661344E+07
return: 3.1661344E+07
return: 3.1661344E+07
return: 3.1661344E+07
return: 3.1661344E+07
return: 3.1661344E+07
return: 3.1661344E+07
return: 3.1661344E+07
【问题讨论】:
不需要使用fortran 90动态数组语法吗? 只是在黑暗中的狂野射击,会不会是调用约定不匹配? 【参考方案1】:此声明“我不能使用 ISO C 绑定,因为它仅适用于 Fortran 2003 及更高版本。”很奇怪;当前任何支持 F90 的编译器也支持大部分或全部 F2003。
正如 Eric Urban 所指出的,在 fortran 中进行数组分配当然是最简单的(实际上您可以使用数组切片或广播来更轻松地进行填充)。但是假设您需要调用一些采用这种形式的 C 例程,只需使用 ISO_C_BINDING 模块在 C 和 fortran 之间进行可移植接口:
program test_real
use, intrinsic :: iso_c_binding
real(kind=c_float), pointer :: realpt(:)
type(c_ptr) :: ptr
integer :: nbr
integer :: i
real :: a=1.0
real :: b=2.0
real :: c=3.0
interface
function getpointer(a, b, c) result(ptr) bind(C,name="getpointer")
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr) :: ptr
real(kind=c_float) :: a, b, c
end function getpointer
end interface
nbr = 9
ptr = getpointer(a, b, c)
call c_f_pointer(ptr, realpt, [nbr])
print *,"return: ",realpt
end
编译运行给出
$ gcc -c fooc.c
$ gfortran -c foo.f90
$ gfortran -o foo foo.o fooc.o
$ ./foo
return: 1.0000000 1.0000000 1.0000000 2.0000000 2.0000000 2.0000000 3.0000000 3.0000000 3.0000000
如果您尝试以某种方式执行此操作来绕过 7 年以上的编译器限制,那么有很多脆弱的不可移植的方法可以做到这一点,但这真的不值得心痛。
更新:如果您不能接触(甚至重新编译)一些较旧的 fortran,那么您至少可以为 C 程序制作一个 F2003 包装器,并将较旧的 fortran 链接到它:
foowrapper.f90:
module wrapper
contains
subroutine wrapgetpointer(outarr)
use, intrinsic :: iso_c_binding
implicit none
real, intent(out), dimension(:) :: outarr
real(kind=c_float), pointer :: realpt(:)
type(c_ptr) :: ptr
integer :: nbr = 9
real(kind=c_float) :: a, b, c
interface
function getpointer(a, b, c) result(ptr) bind(C,name="getpointer")
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr) :: ptr
real(kind=c_float) :: a, b, c
end function getpointer
end interface
a = 1.
b = 2.
c = 3.
ptr = getpointer(a, b, c)
call c_f_pointer(ptr, realpt, [nbr])
outarr(1:nbr) = realpt
end subroutine wrapgetpointer
end module wrapper
foo.f90:
program test_real
use wrapper
real, dimension(9) :: array
call wrapgetpointer(array)
print *,"return: ",array
end
编译运行:
$ gfortran -c foowrapper.f90
$ gfortran -c foo.f90
$ gcc -c fooc.c
$ gfortran -o foo foo.o foowrapper.o fooc.o
$ ./foo
return: 1.0000000 1.0000000 1.0000000 2.0000000 2.0000000 2.0000000 3.0000000 3.0000000 3.0000000
【讨论】:
是的,我知道这是一个奇怪的要求。对我来说更重要的是,目前,我不能保证所有将使用 C 函数的 Fortran 程序都是使用可以使用 ISO C 绑定的编译器编译的。我不知道是否有办法以 Fortran 可以读取的方式返回浮点指针。 在这种情况下,我的建议是编写(并编译)一个调用 C 的 F2003 包装例程,然后让旧的 fortran 调用该例程。 答案已相应更新。虽然如果你真的无法控制旧代码的编译,任何类型的互操作性都可能是不可能的。【参考方案2】:在你的代码中添加隐式 none,你就会明白为什么你没有得到你想要的结果。
Fortran 中的数组值函数通常通过传递一个“隐藏”参数来实现,该参数是函数应该写入其结果的内存地址。这与您的用例没有太多共同之处。
如果您坚持使用 Fortran 90,则无法做到这一点。您需要使用某种扩展。
请注意,从 F2003 开始的 C 互操作性是对 F90 的扩展...
(Cray 指针也是,但如果你必须使用扩展,我知道我会选择哪一个。)
【讨论】:
【参考方案3】:我最终没有实施包装解决方案。对于无法使用 Fortran 2003 的情况,似乎对我有用的是 Cray 指针。我不确定这些在较新的编译器中的可行性,但对于我正在使用的 F90 编译器(英特尔 ifort 9.1),它工作得很好。
Cray 指针可以与返回的 C 指针结合使用。为了在 Fortran 中将 Cray 指针声明为浮点数组,例如:
real, dimension(10) :: realpt
pointer (ptemp,realpt)
nbr = 9
然后你可以像这样调用C函数:
ptemp = getpointer(a, b, c)
do 10 i = 1, nbr
print *,"return: ",realpt(i)
10 continue
这是一个解释如何使用 Cray 指针的资源:
http://gcc.gnu.org/onlinedocs/gfortran/Cray-pointers.html
【讨论】:
以上是关于无法从 Fortran 90 中返回的 C 浮点指针获取数据的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Inquire pos 在 Fortran 90 中返回 0