I am trying to call a C++ function in a Fortran subroutine. This C++ function is supposed to update an integer array. Here is a non-working code I wrote. What is the issue?
! Fortran function that calls a C++ function.
subroutine my_function()
integer(4) ar(*)
integer(4) get_filled_ar
! Need correct syntax here.
ar = get_filled_ar()
end
// C++ function:
extern "C" {
void get_filled_ar(int *ar){
ar[0] = 1;
ar[1] = 10;
ar[3] = 100;
}
}
With Fortran 2003 there is a standard and thus platform and compiler independent way to call C from Fortran, and also any language that uses the C calling interface. Also to call Fortran from C. While the various compiler writers are gradually adding Fortran 2003 features and there are few complete 2003 compilers, the ISO C Binding has been available for some time in many compilers. The ISO C Binding works better than the previous ad hoc techniques, which were sometimes poorly documented, and varied between compilers and platforms. To call C from Fortran, you write an "interface" that tells the Fortran compiler that it should use the C calling conventions, and C types.
Here is an example. As Mike wrote, since the C++ function returns void, treat it in the Fortran as a subroutine and call it. Thus it doesn't need to be given a type. Also, somewhere in the Fortran you have to reserve storage for the array -- the easiest way is with a declaration with numeric value for the dimension. And you need a main program in some language.
program test_call_C
use iso_c_binding
implicit none
interface c_interface
subroutine get_filled_ar (ar) bind (C, name = "get_filled_ar")
use iso_c_binding
implicit none
integer (c_int), intent (out), dimension (*) :: ar
end subroutine get_filled_ar
end interface c_interface
integer (c_int), dimension (0:3) :: ar
call get_filled_ar (ar)
write (*, *) "Fortran: ar:", ar
stop
end program test_call_C
and in C:
void get_filled_ar (
int ar []
) {
ar [0] = 1;
ar [1] = 10;
ar [2] = 100;
return;
}
Example commands:
gcc -c get_filled_ar.c
gfortran get_filled_ar.o test_call_C.f90 -o test_call_C.exe
./test_call_C.exe
To call your C++ code, use the following commands. The name specified in the "bind" obviates the need for a trailing underscore so your C++ code works directly.
g++ -c cplusplus.cc
gfortran cplusplus.o test_call_C.f90 -o test_call_Cplusplus.exe
./test_call_Cplusplus.exe
Here's a full program with your code in it that should work (at least on linux with gcc
/gfortran
).
In the fortran file fortran.f
, put:
IMPLICIT NONE
CALL my_function()
END
! FORTRAN function that calls a C++ function
subroutine my_function()
! Tell fortran about the C++ function:
external get_filled_ar
integer ar(4)
! As the C++ function returns void, call it as a subroutine in
! fortran:
call get_filled_ar(ar)
! To check it worked, print out the numbers:
do i = 1,4
write(*,*) i,"->",ar(i)
enddo
end
In cplusplus.cc
put:
extern "C"
{
void get_filled_ar_(int* ar) // note extra underscore to keep linker happy
{
ar[0] = 1;
ar[1] = 10;
ar[3] = 100;
}
}
Then build (on linux with gcc
/gfortran
, might be different on other systems) with:
gfortran -c fortran.f
gcc -c cplusplus.cc
gfortran -o program-name fortran.o cplusplus.o
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With