问题描述
我决定将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
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下则不具有:这是该语言的一个相对较新的功能,易于在实现时出错(或在使用时)。不允许使用此语言的语言解释)。