Fortran-C 互操作性和浮点数组 [英] Fortran-C interoperability and float arrays

查看:14
本文介绍了Fortran-C 互操作性和浮点数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个大型的现有 Fortran95 代码.它使用

I have a large existing Fortran95 code. It uses

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

声明数组.

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

I want to join in some C code and found that I can do this by writing interfaces to the C-functions and declaring arrays as

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

我有调用 C 函数的 fortran 函数

I have working fortran functions which call the C-functions as

call myfunction(c_loc(array));

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

What is needed to pass the real(dp) array to myfunction? Apparently, I would need to make a C-pointer from it (how?). Is there any other way than copying the array? Is it possible to ensure that both types indeed refer to compatible double precision data blocks? Most importantly the solution must work with the GNU compilers. Note, that replacing real(dp) with real(c_double) everywhere in the existing Fortran code is not an option for me right now.

如果无法复制整个数组,我将如何在界面中正确执行此操作?

In case there is no alternative to copying the entire array, how would I do this properly in the interface?

推荐答案

首先,我假设您将 dp 定义为模块中某处的参数.你可以简单地使用

First, I assume you define dp as a parameter in a module somewhere. You can simply use

integer, parameter :: dp = c_double

在该模块中(并让 if (dp/= c_double) 在某处停止Bletchful sytem".

在 C 和 Fortran 之间传递数组的工作方式如下:

Passing an array between C and Fortran works like this:

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 函数的方法是

The way to call your C function from Fortran would then be

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:

如果你真的想每次都抄入/抄出,你可以这样做

If you really want to do copy-in / copy-out each time, you can do something like

  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

但我不明白为什么这是必要的.

But I am at a loss to understand why this would be necessary.

编辑 3:

如果您担心 C 和 Fortran 数据类型之间不匹配,您可以编写一个通用包装器来解决这个问题.它可能是这样的:

If you are afraid of a mismatch between C and Fortran datatypes, you can write a generic wrapper to get around this. This is what it could look like:

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

你的主程序可能看起来像

Your main program then could look like

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 的包装函数,则编译将因缺少通用过程而失败.

where you don't make any reference to iso_c_binding at all. If there is no wrapper function for dp or sp, compilation will fail for lack of a generic procedure.

这篇关于Fortran-C 互操作性和浮点数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆