我应该在C端未定义的子例程旁边放置“ bindC”吗?

问题描述

说,我有一个C ++函数,必须在Fortran库中实现。

我决定将Fortran包装器封装在一个模块中,如下所示。

(C ++方面)

extern "C" void cpp_func1(int* n,int* array) { ... }

(在Fortran方面)

module cpp2fortran
  use ISO_C_BINDING
  implicit none

  interface
! (1)
    subroutine cpp_func1(n,array) bind(C)
      use iso_c_binding
      integer(C_INT),intent(in) :: n
      type(C_PTR),value,intent(in) :: array
    end subroutine
  end interface  

contains

! (2)
    subroutine Utilize_cpp_func1( ... )  ! bind(C)
    use iso_c_binding

    ...

    call cpp_func1(...)

    ...

  end subroutine

end module

我在两个地方标记了数字,例如(1)和(2)。

在(1)的最后,我肯定放了bind(C),没有它,代码将无法编译。

问题是,我应该将bind(C)放在(2)的末尾吗?

代码的编译/工作与行(2)末尾bind(C)的存在无关,但是我发现如果我将bind(C)放在其中,某些类似于Fortran的优化将不起作用

例如,在没有bind(C)的普通Fortran中,

real,allocatable :: arr1(:)
real,allocatable :: arr2(:)

...

arr2 = arr1

...

可以正常工作。但是,如果我输入bind(C),它将无法正常工作,因此我必须进行如下修改

real,allocatable :: arr2(:)

...

do i = 1,size
  arr2(i) = arr1(i)
enddo

...

如果可以安全地从类似(2)的Fortran包装器中删除bind(C),我很乐意将其删除并使用诸如arr2 = arr1之类的简洁优化方法,而不是花费冗长的代码编写所有do循环


这是bind(C)引起问题的最小示例。我用ifort编译它。

module cbind
  use iso_c_binding
  implicit none
contains
(*) subroutine sub1(array) !bind(C)
    use iso_c_binding
    implicit none
    real,allocatable,intent(in) :: array(:)

    real(C_FLOAT),target :: array_target(:)

    allocate( array_target(size(array,1)) )

    array_target = array

    print *,'array'
    print *,array
    print *,'array_target'
    print *,array_target

  end subroutine
end module

program test
  use iso_c_binding
  use cbind
  implicit none
  real,allocatable :: array(:)

  allocate( array(5) )

  array = 1.0

  call sub1(array)

end program

在行(*)处没有bind(C)的情况下,代码可以在所需的输出上正常工作。

array
  1.000000       1.000000       1.000000       1.000000       1.000000  
array_target
  1.000000       1.000000       1.000000       1.000000       1.000000  

但是,如果我放bind(C),则代码段会显示以下输出

 array
   1.000000       1.000000       1.000000       1.000000       1.000000    
 array_target
forrtl: severe (174): SIGSEGV,segmentation fault occurred
Image              PC                Routine            Line        Source   
cbinding1          00000000004051B3  UnkNown               UnkNown  UnkNown
libpthread-2.17.s  00002AC983A5E5F0  UnkNown               UnkNown  UnkNown
cbinding1          000000000045382A  UnkNown               UnkNown  UnkNown
cbinding1          000000000042B967  UnkNown               UnkNown  UnkNown
cbinding1          000000000040FCB3  UnkNown               UnkNown  UnkNown
cbinding1          000000000040CA01  UnkNown               UnkNown  UnkNown
cbinding1          0000000000403C1B  UnkNown               UnkNown  UnkNown
cbinding1          00000000004037E2  UnkNown               UnkNown  UnkNown
libc-2.17.so       00002AC983C8D505  __libc_start_main     UnkNown  UnkNown
cbinding1          00000000004036E9  UnkNown               UnkNown  UnkNown

解决方法

过程的BIND属性对于使其可与C互操作是必需的。尽管它具有其他效果,但是对于Fortran过程而言,该属性对于能够利用可互操作过程本身并不是必需的。更具体地说,不可互操作的过程可能会使用不可互操作的过程:一个人可能会大量使用这一非常有用的事实。

就您而言(从我们的角度来看),您不需要bind(c)上的Utilize_cpp_func1定义。此过程本身不需要C可以互操作。

引起对array_target = array的关注,这只是某些英特尔编译器版本中的编译器弱点。它在当前版本中不存在。

在这个示例中,bind(c)为什么会有所作为?您的伪参数array是可分配的。一个可互操作的过程可能仅在Fortran 2008 + TS29113或Fortran 2018下才具有可分配的哑元参数,而在Fortran 2003或Fortran 2008下则不具有:这是该语言的一个相对较新的功能,易于在实现时出错(或在使用时)。不允许使用此语言的语言解释)。