我有一个很大的现有Fortran95代码。它使用
real(dp), dimension(num) :: array
声明数组。
我想加入一些C代码,发现我可以通过编写C函数接口并将数组声明为
来实现这一点use iso_c_binding
real(c_double), allocatable, target :: array(:)
我有使用fort函数调用C函数
call myfunction(c_loc(array));
将real(dp)
数组传递给myfunction需要什么?显然,我需要从它做一个C指针(如何?)。复制数组还有其他方法吗?是否有可能确保两种类型确实引用兼容的双精度数据块?最重要的是,该解决方案必须与GNU编译器一起使用。请注意,现在使用现有Fortran代码中的real(dp)
取代real(c_double)
不是我的选择。
如果没有其他方法可以复制整个阵列,我将如何在界面中正确执行此操作?
答案 0 :(得分:4)
首先,我假设您将dp定义为某个模块中的参数。你可以简单地使用
integer, parameter :: dp = c_double
在该模块中(并在某处if (dp /= c_double) stop "Bletchful sytem"
。
在C和Fortran之间传递数组的工作原理如下:
module foo
use iso_c_binding
private
public :: bar
interface
subroutine bar(a,n) bind(C)
import
real(kind=c_double), dimension(*), intent(inout) :: a
integer(c_size_t), value, intent(in) :: n
end subroutine bar
end interface
end module foo
那么你的C函数就是
void bar(double *a, size_t n)
修改强>
从Fortran调用C函数的方法就是
program main
use iso_c_binding
use foo
real(c_double), dimension(10) :: a
call bar(a,size(a,kind=c_size_t))
print *,a
end program main
编辑2:
如果您真的想每次都进行复制/复制,您可以执行类似
的操作 subroutine bar2(array)
real(kind=c_double), intent(inout), dimension(:) :: array
real(kind=c_double), dimension(size(array)) :: a
a = array ! Copy in
call bar(a,size(a,kind=c_size_t))
array = a ! Copy out
end subroutine bar2
end module foo
但我不知道为什么这是必要的。
编辑3:
如果您害怕C和Fortran数据类型之间的不匹配,您可以编写一个通用的包装器来解决这个问题。这就是它的样子:
module foo
use iso_c_binding
implicit none
private
public :: bar
interface
subroutine bar_double(a,n) bind(C)
import
real(kind=c_double), dimension(*), intent(inout) :: a
integer(c_size_t), value, intent(in) :: n
end subroutine bar_double
end interface
interface
subroutine bar_float(a,n) bind(C)
import
real(kind=c_float), dimension(*), intent(inout) :: a
integer(c_size_t), value, intent(in) :: n
end subroutine bar_float
end interface
interface bar
module procedure bar_aux_double, bar_aux_float
end interface bar
contains
subroutine bar_aux_double (a)
real(kind=c_double), dimension(:), intent(inout) :: a
call bar_double (a, size(a,kind=c_size_t))
end subroutine bar_aux_double
subroutine bar_aux_float (a)
real(kind=c_float), dimension(:), intent(inout) :: a
call bar_float (a, size(a,kind=c_size_t))
end subroutine bar_aux_float
end module foo
您的主程序可能看起来像
program main
use foo
integer, parameter :: dp = selected_real_kind(15)
integer, parameter :: sp = selected_real_kind(6)
real(dp), dimension(10) :: a_dp
real(sp), dimension(10) :: a_sp
call bar(a_dp)
call bar(a_sp)
print *,a_dp,a_sp
end program main
你根本不提及iso_c_binding。如果dp或sp没有包装函数,则由于缺少通用过程,编译将失败。
答案 1 :(得分:1)
如果你使用模块,在Fortran中混合dp
和c_double
时不要太担心。在非常不可能的情况下,selected_real_kind(15, 307) /= c_double
编译器在检查过程接口时会抱怨。否则,它会看到类型数字一致,并且它不关心你如何调用类型常量(除非声明可互操作的程序)。