简体   繁体   中英

Fortran/C interoperability passing a struct from Fortran to C with allocatables

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!

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM