Under the rules of current Fortran (Fortran 2008, but this is the same for when C interoperability was introduced in Fortran 2003), a Fortran procedure is not interoperable with C if it has an assumed shape dummy argument (other restrictions also apply). In your code degC
, the dummy argument in the function DegCtoF
, declared as
real(c_double), intent(in), dimension(:) :: degC
is such a thing.
So, under F2003 you cannot have such an interoperable function. Which is where things get tricky.
In the proposed draft for F2015 (based on the ISO TS29113 Further Interoperability of Fortran with C) such a thing is interoperable. And this syntax is (I think) supported by recent versions of gcc which is why the code is not rejected by gfortran.
(TS) Standardized interoperation with such a procedure with an assumed shape argument, however, requires using the C descriptor described in ISO_Fortran_binding.h
on the C side which is not implemented in gcc. To do such interaction instead requires understanding the gcc array descriptor directly.
But you're in luck. In your case you don't really need to use an assumed shape dummy argument: you can use an explicit shape dummy argument and such interoperation is part of F2003. All you need to do is pass the size of the array.
Either way, an interoperable function must return a scalar result, so you'll also want to move to a subroutine, as given in the answer by innoSPG.
Finally, I'll mention your use of
real(c_double), bind(c) :: degF, degC
in the module.
These are interoperable global variables (through linkage association). You don't reference these variables in the Fortran code: the dummy and the function result are not these things.
In this simple case from the above, and the other answer, one will happily have a subroutine like
subroutine DegCtoF(n, degC, degF) bind(c,name='DegCtoF')
...
end subroutine
but this is perhaps a good opportunity to describe the use of the C descriptor from ISO_Fortran_binding.h
. Note, though, that in the immediate term gfortran does not support this approach.
Consider the Fortran source
subroutine DegCtoF(degC, degF) bind(c,name='DegCtoF')
use, intrinsic :: iso_c_binding, only : c_double
implicit none
real(c_double), intent(in), dimension(:) :: degC
real(c_double), intent(out), dimension(*) :: degF
degF(1:SIZE(degC)) = degC*1.8+32
end subroutine DegCtoF
(for simplicity I'm going to assume that the memory management of degF
is done all on the C side - naturally one could extend beyond the assumed size array). For this subroutine to be interoperable the argument corresponding to degC
must be a pointer to CFI_cdesc_t
.
Take the C code (with size magic numbers)
#include "ISO_Fortran_binding.h"
#include <stdio.h>
void DegCtoF(CFI_cdesc_t*, double*);
int main(int argc, char *argv[])
{
printf("C and Fortran together!
");
CFI_CDESC_T(1) DegreesC_Fdesc;
CFI_index_t extent[1] = {2};
CFI_rank_t rank = 1;
double DegreesC[2] = {32, 64};
double DegreesF[2];
CFI_establish((CFI_cdesc_t*)&DegreesC_Fdesc, &DegreesC, CFI_attribute_other,
CFI_type_double, 2*sizeof(double), rank, extent);
DegCtoF((CFI_cdesc_t*)&DegreesC_Fdesc, DegreesF);
printf("%3.1f [C] = %3.1f [F]
", DegreesC[0], DegreesF[0] );
printf("%3.1f [C] = %3.1f [F]
", DegreesC[1], DegreesF[1] );
return 0;
}
Here CFI_establish
establishes a suitable C descriptor DegreesC_Fdesc
which can correspond to the assumed shape Fortran dummy argument. Inside the Fortran subroutine there is no problem at all assessing the size of the incoming array.