Say, I have a C++ functions that I have to implement into the Fortran library.
I decided to make my Fortran wrapper in a module, which goes like below.
(C++ side)
extern "C" void cpp_func1(int* n, int* array) { ... }
(Fortran side)
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
I marked numbers at two places, e.g. (1) and (2).
At the end of the (1), I definitely put bind(C)
, and without it the code fail to be compiled.
The thing is, should I put bind(C)
at the end of (2)?
The code compiles/works just fine independent from the presence of bind(C)
at the end of the line (2), but I found that some Fortran-like optimization do not work if I put bind(C)
.
For example, in normal Fortran without bind(C)
,
real, allocatable :: arr1(:)
real, allocatable :: arr2(:)
...
arr2 = arr1
...
would work fine. However, if I put bind(C)
, it does not work and I had to make some modification such as following
real, allocatable :: arr1(:)
real, allocatable :: arr2(:)
...
do i = 1, size
arr2(i) = arr1(i)
enddo
...
If it's safe to remove bind(C)
from the (2)-like Fortran wrapper, I would happy to remove it and exploit the concise optimization such as arr2 = arr1
rather than make lengthy code writing all do loops.
This is the minimum example in which bind(C)
makes a problem. I used ifort to compile it.
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), allocatable, 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
Without bind(C)
at the line (*), the code just works fine with the desired output.
array
1.000000 1.000000 1.000000 1.000000 1.000000
array_target
1.000000 1.000000 1.000000 1.000000 1.000000
However if I put bind(C)
, the code segfaults with following output.
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
The BIND attribute for a procedure is necessary to make it C interoperable. Although it has other effects, the attribute is not necessary for a Fortran procedure to be able to make use of an interoperable procedure itself. More specifically, a procedure which is not interoperable may use a non-interoperable procedure: one is likely to use this very useful fact a lot.
In your case (from what we see), you do not need bind(c)
on the definition of Utilize_cpp_func1
. This procedure itself is not required to be C interoperable.
Coming to the concern about array_target = array
, this simply is a compiler weakness in some versions of the Intel compiler. It is not present in the current release.
Why does bind(c)
make a difference in this example? Your dummy argument array
is allocatable. An interoperable procedure may have an allocatable dummy argument only under Fortran 2008+TS29113 or Fortran 2018, not under Fortran 2003 or Fortran 2008: it's a relatively new feature of the language and susceptible to things going a bit wrong in its implementation (or when using interpretations of the language which don't allow this feature).