的Fortran-C的互操作性和浮动阵列 [英] Fortran-C interoperability and float arrays

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

问题描述

我有一个大现有Fortran95 code。它采用

I have a large existing Fortran95 code. It uses

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

要声明数组。

我想在一些C code加入,我发现我可以通过写接口的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-功能

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

call myfunction(c_loc(array));

什么是需要通过实(DP)数组MyFunction的?很显然,我需要从中进行C-指针(如何?)。是否有任何其他方式比复制数组?是有可能确保这两种类型的确参考兼容双precision数据块?最重要的是解决方案,必须与GNU编译器。请注意,以实(c_double)替换实(DP) 在现有的Fortran code无处不在对我来说现在的选项。

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

(和

在该模块中有如果(DP / = c_double)停止Bletchful系统正的某个地方。

在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函数是

Your C function then would be

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天全站免登陆