Fortran-C互操作性和浮点数组

高学历

我有一个很大的现有Fortran95代码。它用

real(dp), dimension(num) :: array

声明数组。

我想加入一些C代码,发现可以通过编写C函数的接口并将数组声明为

use iso_c_binding
real(c_double), allocatable, target :: array(:)

我有正在使用的fortran函数,它们将C函数称为

call myfunction(c_loc(array));

real(dp)数组传递给myfunction需要什么显然,我需要用它做一个C指针(怎么做)。除了复制阵列还有其他方法吗?是否可以确保两种类型的确引用了兼容的双精度数据块?最重要的是,该解决方案必须与GNU编译器一起使用。请注意,现在对我来说,在现有Fortran代码中替换real(dp)real(c_double)任何地方都不是一个选择。

如果没有其他方法可以复制整个阵列,我该如何在界面中正确执行此操作?

用户名

首先,假设您将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的包装函数,则编译将由于缺少通用过程而失败。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章