I have a Fortran derived type with a matching C struct. I am creating an array of the derived type, and I want to pass this array to a C function. Here is my Fortran code
module tmod
use iso_c_binding
integer, parameter :: nstring = 22
integer, parameter :: ntype = 3
!! Type with a bind(c)
type, bind(c) :: mystruct
character (c_char) :: hello (nstring)
character (c_char) :: world (nstring)
integer (c_int) :: ii
end type mystruct
interface !! Function on the C side
integer (c_int) function testfunc (t, asize) bind(C, name="testfunc")
use iso_c_binding
import mystruct
type (mystruct) :: t (:) !< array of struct/derived type
integer (c_int), value :: asize !< Size of the array
end function testfunc
end interface
end module tmod
program testprog
use tmod
use iso_c_binding
type(mystruct), target :: t (0:ntype-1) !< Array of derived type set up with C-like indicies
integer (c_int) :: i
!! Initialize the struct array
do j = 0,ntype-1
t(j)%hello = "HelLo"//c_null_char
t(j)%world = "World"//c_null_char
t(j)%ii = j-3
enddo
!! Call C function
i = testfunc(t, ntype)
end program testprog
My C code loops through the struct and prints the integer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int const nstring = 22; /* matches string size from fortran */
struct mystruct{
char hello[22];
char world[22];
int ii ;
}mystruct;
int testfunc (struct mystruct * t[], int asize ) {
/* Loop through array and print index then ii value */
for (int j = 0; j < asize ; j++) {
printf ("%d \n", j);
printf ("%d \n", t[j]->ii);
}
return 0;
}
These compile with icc version 2021.5.0 and ifort version 2021.5.0 or gcc version 11.2.0 (this drops a note about declared here for mystruct t[]). It prints out the result of the first loop. It gives me a segmentation fault on the second pass through the loop. I can't pass the array by value because it is an array and that's apparently not allowed.
If I define my C function without the pointer
int testfunc (struct mystruct t[], int asize )
the program runs to the end, but does not print the correct information. How can I pass this Fortran array to the C function?
Your Fortran interface has an assumed-shape dummy argument
t. The interface fortestfuncwith this assumed-shape array is not interoperable with the formal parameterstruct mystruct * t[]of the C function. An interoperable C function must have the argument associated with a pointer toCFI_cdesc_tobject.That said, there's little reason in the code you show to want to use an assumed-shape dummy argument, seeing as you are also passing the size of the array. Instead use an explicit-shape argument:
Which is then going to lead to the next problem: you don't want
struct mystruct * t[]butstruct mystruct *:Alternatively, if for some reason you do need the assumed-shape argument:
you can make that interoperable with
Either way, you'll probably want to address the assignments like
which sets the array
t(j)%helloto 22 elements of"H". You'll want the right-hand side to itself be an array of 22 elements, say:And don't forget to use
implicit noneliberally to reduce the surprise potential.