Reputation: 51
I am trying pass a struct from fortran to C, where the struct in Fortran has an allocatable. I would like to allocate the array inside a struct in fortran and read it in C. However, when I try to print the allocated array in C I get an error message segmentation fault (core dumped). I am using Intel compiler verison 19.0.1.144.
I am relatively new to C, so to test this idea i allocated a one dimensional array in fortran and passed it to C. This works very well. You can see in the fortran code that ff is allocatable array and it is allocated a dimension ii (which is equal to 5). I initialize the array ff and use pointer of type(C_ptr) to store the address of the array of ff. I print of ff in C and it prints the correct values ff which is 14.7,15.7,16.7,17.7,18.7. Using the same idea, I have declared a struct data1 with an integer ival, a real cval and an allocatable variable dval. I am allocating a pointer pdata for for the struct type data1. I allocate the pointer and the array dval. I call the fortran in my C Main to print the struct quantities and I get an error when i print the array d (or dval). Furthermore, the values of the values of ival and cval in C are incorrect.
SUBROUTINE Simulation(ii,ffp,cdata) BIND(C)
use, intrinsic :: iso_c_binding
integer(kind=4), intent(in) :: ii
type(C_PTR), intent(out) :: ffp
real (C_double), dimension(:), allocatable, target, save :: ff
integer(kind=4) :: err, i
Type :: data1
Integer :: ival
Real :: cval
Real (C_double), dimension(:), allocatable :: dval
end Type data1
type(C_ptr), intent(out) :: cdata
type(data1), Target, save :: tdata
type(data1), pointer :: pdata
!Allocating memory for pdata:
Allocate(pdata,stat=err)
print *,'allocate returned: ',err
!Allocating memory for dval:
allocate(pdata%dval(ii),stat=err)
print *,'allocate returned: ',err
!Allocating memory for ff:
allocate(ff(ii),stat=err)
print *,'allocate returned: ',err
ffp = C_LOC(ff(1))
cdata = C_Loc(pdata)
pdata%ival = 4
pdata%cval = 17.6
pdata%dval(1) = 1.2
pdata%dval(2) = 1.2*2
pdata%dval(3) = 1.2*3
pdata%dval(4) = 1.2*4
pdata%dval(5) = 1.2*5
print*,"ival = ",pdata%ival
print*,"cval = ",pdata%cval
print*,"davl(1) = ",pdata%dval(1)
print*,"davl(4) = ",pdata%dval(4)
write(*,*) '#Fortran address of ff:', LOC(ff(1))
write(*,*) '#Fortran address: pdata', LOC(pdata)
write(*,*) 'size of ff =',sizeof(ff)
write(*,*) 'size of pdata =',sizeof(pdata)
do i=1,ii
ff(i) = i + 13.7d0
end do
END SUBROUTINE SIMULATION
The c code calling the fortran subroutine is
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct temp {int ival; float cval; double *d;};
void simulation(int *ii, double **ff, struct temp *data2);
int main()
{
int ii = 5;
double *ff;
struct temp data2;
int i;
simulation(&ii,&ff,&data2);
printf("#C address of ff: %d\n", ff);
printf("#C address of data2: %d\n", data2);
printf("Size of ff in C is %d\n", sizeof(ff));
for (i=0; i<ii; i++)
printf("ff[%d] = %f\n",i,ff[i]);
printf("data ival %d \n",data2.ival);
printf("data cval %f \n",data2.cval);
printf("data dval(1) %f \n",data2.d[0]);
printf("data dval(4) %f \n",data2.d[3]);
return 0;
}
The output on the terminal
bash-4.2$ ./a.out
allocate returned: 0
allocate returned: 0
allocate returned: 0
ival = 4
cval = 17.60000
davl(1) = 1.20000004768372
davl(4) = 4.80000019073486
#Fortran address of ff: 26650144
#Fortran address: pdata 26636320
#Fortran address: tdata 7054304
size of ff = 40
size of pdata = 80
size of tdata = 80
#C address of ff: 26650144
#C address of data2: 26636320
Size of ff in C is 8
ff[0] = 14.700000
ff[1] = 15.700000
ff[2] = 16.700000
ff[3] = 17.700000
ff[4] = 18.700000
data ival 26636320
data cval 0.000000
Segmentation fault (core dumped)
You can see that ival is 4 and cavl is 17.6 in fortran but in C ival is the address of the struct data2, cval = 0.0. I am not able to figure out what is going wrong. My apologies for pasting the whole code in the forum, I couldn't figure out a way to explain it better. I will be grateful to any suggestions/help in thsi regard. Thank you in advance!
Upvotes: 5
Views: 1066
Reputation: 32451
The derived type data1
is not C-interoperable: it has an allocatable component. The intent(out)
dummy argument cdata
is assigned the result of C_LOC(pdata)
where pdata
is of this non-interoperable type.
C_LOC
returns an "opaque handle" to the actual argument when that argument is not interoperable. The implication of this is (Fortran 2018 18.2.3.6):
Where the actual argument is of noninteroperable type or type parameters, the result of C_LOC provides an opaque “handle” for it. In an actual implementation, this handle might be the C address of the argument; however, only a C function that treats it as a void (generic) C pointer that cannot be dereferenced (ISO/IEC 9899:2011, 6.5.3.2) is likely to be portable.
You attempt such non-portable dereferencing in the C main with data2
. Fundamentally, an allocatable Fortran array is not the same thing as a C dereferenced pointer.
You may portably pass this handle data2
back to a Fortran procedure for further processing. Fortran procedures may even be interoperable when dummy arguments are allocatable arrays.
Upvotes: 3