Pass arrays from C/C++ to Fortran and return a calculated array
Before francescalus confirms it, I was going to say that from what I know that was a little bit old, the interoperability does not permit what you are trying to do with arrays.
In addition, some good habits are always critical when coding. For example using implicit none
in fortran to force the declaration of all variables before they are used. The use of named constant when the language permits it, for example the 2
that you are using as array size in fortran.
Below is a modified version of your code that should do something like what you want to achieve.
//Fortran
module ConvertUnitsLib
use :: iso_c_binding ! for C/C++ interop
!real(c_double), bind(c) :: degF, degC
implicit none
public DegCtoF
contains
!
! Convert temperature degrees Celsius Fahrenheit
!
subroutine DegCtoF(degC, degF, n)&
bind(c, name = "DegCtoF")
integer, intent(in) :: n
real(c_double), intent(in), dimension(n) :: degC
real(c_double), intent(out), dimension(n) :: degF
integer :: i
do i = 1, n
degF(i) = ( degC(i) * 1.8 ) + 32
end do
end subroutine DegCtoF
// C++
#include <stdio.h>
#ifdef __cplusplus
extern"C" {
#endif
double DegCtoF(double [], double [], const int *);
#ifdef __cplusplus
}
#endif
/**********************************************************************/
int main(int argc, char *argv[])
{
const int N = 2;
printf("C/C++ and Fortran together!\n");
double DegreesC[N] = {32, 64};
double DegreesF[N];
DegCtoF(DegreesC, DegreesF, &N);
for(int i = 0; i<N; i++){
printf("%d : %3.1f [C] = %3.1f [F]\n", i, DegreesC[i], DegreesF[i] );
}
return 0;
}
How to pass array to a procedure which is passed as an argument to another procedure using Fortran
It's the assumed-shape array dummy arguments dimension(:)
that require an explicit interface. This is because the compiler has to do something different for these, typically passing a descriptor. It doesn't matter what's on the calling side, it's the dummy arguments of the called procedure that matter.
For more information see my old blog post Doctor Fortran Gets Explicit - Again!
You may want to look at the language feature abstract interface
, along with procedure
, to make the code look a bit cleaner.
How to access (dynamically allocated) Fortran arrays in C
In my opinion it is not good practice to try to access global data in Fortran library. It can be done using COMMON blocks, but they are evil and require statically sized arrays. Generally storage association is a bad thing.
Never access the module symbols as "__bar_MOD_a" they are compiler specific and not meant to be used directly. Pass poiters using functions and subroutines.
Pass the array as a subroutine argument. You can also allocate the array in C and pass it to Fortran. What can be also done is getting a pointer to the first element of the array. It will serve es the C pointer to the array.
My solution, for simplicity without the .so, it is trivial to add it:
bar.f90
module bar
use iso_C_binding
implicit none
integer, parameter :: pa = selected_real_kind(15, 307)
real(pa), dimension(:), allocatable,target :: a
integer :: as
contains
subroutine allocArray(asize,ptr) bind(C,name="allocArray")
integer, intent(in) :: asize
type(c_ptr),intent(out) :: ptr
as = asize
allocate(a(asize))
ptr = c_loc(a(1))
end subroutine
subroutine fillArray(values) bind(C,name="fillArray")
real(pa), dimension(as), intent(in) :: values
a = values
end subroutine
subroutine printArray() bind(C,name="printArray")
write(*,*) a
end subroutine
end module
main.c
#include <dlfcn.h>
#include <stdio.h>
int main()
{
int i, k = 4;
double arr[k];
char * e;
double *a;
void allocArray(int*,double**);
void fillArray(double*);
void allocArray();
for(i = 0; i < k; i++)
arr[i] = i * 3.14;
allocArray(&k,&a);
fillArray(arr);
printArray();
for(i = 0; i < 4; i++)
printf("%f ", a[i]);
printf("\n");
return 0;
}
compile and run:
gcc -c -g main.c
gfortran -c -g -fcheck=all bar.f90
gfortran main.o bar.o
./a.out
0.0000000000000000 3.1400000000000001 6.2800000000000002 9.4199999999999999
0.000000 3.140000 6.280000 9.420000
Note: There is no reason for the returns in your Fortran subroutines, they only obscure the code.
Related Topics
Can a Variable Be Declared Both Static and Extern
What Is the Purpose of the _Chkstk() Function
Should Std::Common_Type Use Std::Decay
Why "Not All Control Paths Return a Value" Is Warning and Not an Error
C++ Static Const Access Through a Null Pointer
Difference Between Regex_Match and Regex_Search
How to Pass a Std::Function Object to a Function Taking a Function Pointer
Opencv on MAC Is Not Opening Usb Web Camera
Deleted Function in Std::Pair When Using a Unique_Ptr Inside a Map
Calculating the Info-Hash of a Torrent File
Std::Vector Capacity After Copying
C++ Circular Dependency in Header Files
Using Visual Studio Project Properties Effectively for Multiple Projects and Configurations
Difference Between Std::Function<> and a Standard Function Pointer