Home > Software engineering >  Shared data structure between C and Fortran, good on C side, bad on Fortran side
Shared data structure between C and Fortran, good on C side, bad on Fortran side

Time:01-25

I am trying to pass a structure "stuff" from C to Fortran. "stuff" has a member "gef" which contains two variables, "name" and "extra". Before the call to the Fortran routine test2, both stuff.gef and stuff_gef are good, But when I enter the Fortran, the "name" and "extra" variables are bad.

(Ideally, I'd like to populate stuff.gef directly without having to go through an intermediary stuff_gef)

C code:

#include <iostream>
#include <cstddef>
#include <vector>

using namespace std;

extern "C" {
    struct t_stuff_gef {
      char   name[256];
      double extra;
    };
    struct t_stuff {
      t_stuff_gef *gef;
    };
    void test2(t_stuff *stuff);
}

int main()
{
    t_stuff stuff;
    t_stuff_gef stuff_gef;

    strcpy_s(stuff_gef.name, sizeof(stuff_gef.name), "Teststuff");
    stuff_gef.extra = 100.0;

    stuff.gef = &stuff_gef;

    test2(&stuff);
}

Fortran code:

module ftncode_mod
   use, intrinsic :: iso_c_binding
   implicit none

   type, public, bind(C) :: t_stuff_gef_ext
     character(1) :: name(256)
     real(8)      :: extra
   end type t_stuff_gef_ext

   type, public, bind(C) :: t_stuff_ext
     type(t_stuff_gef_ext) :: gef
   end type t_stuff_ext

    contains
      subroutine test2(stuff_ext) bind(C)
      !DEC$ATTRIBUTES DLLEXPORT :: test2
        use, intrinsic :: iso_c_binding
        type(t_stuff_ext), target , intent(in) :: stuff_ext
        continue       
        return
      end

end module

CodePudding user response:

The following code does what you want. The important point is to bind the Fortran types to C, and to declare a c_ptr when a pointer is declared on the C side.

#include <iostream>
#include <cstddef>
#include <vector>
#include <string.h>

using namespace std;

extern "C" {
    struct t_stuff_gef {
      char   name[256];
      double extra;
    };
    struct t_stuff {
      t_stuff_gef *gef;
    };
    void test2(t_stuff *stuff);
}

int main()
{
    t_stuff stuff;
    t_stuff_gef stuff_gef;

    strncpy(stuff_gef.name,"Teststuff",256);
    stuff_gef.extra = 100.0;

    stuff.gef = &stuff_gef;

    printf("%s\n%f\n\n",stuff_gef.name,stuff_gef.extra);
    test2(&stuff);
}
module ftncode_mod
   use, intrinsic :: iso_c_binding
   implicit none

   type, public, bind(C) :: t_stuff_gef_ext
     character(256) :: name
     real(c_double) :: extra
   end type t_stuff_gef_ext

   type, public, bind(C) :: t_stuff_ext
     type(c_ptr) :: gef_cptr   ! for consistency with the C struct
   end type t_stuff_ext

   contains
      subroutine test2(stuff_ext) bind(C)
        type(t_stuff_ext) , intent(in) :: stuff_ext
        type(t_stuff_gef_ext), pointer :: gef

        call c_f_pointer(stuff_ext%gef_cptr, gef) ! convert the C pointer to a Fortran pointer

        write(*,*) gef%name
        write(*,*) gef%extra
      end

end module

Compilation:

%gfortran -c cfinteropf.f90 ; g   cfinterop.cpp cfinteropf.o -lgfortran && a.out
Teststuff
100.000000

 Teststuff
   100.00000000000000  

CodePudding user response:

My solution.

C Code:

#include <iostream>
#include <cstddef>
#include <vector>

using namespace std;

extern "C" {
    struct t_stuff_gef {
      char   name[256];
      double extra;
    };
    struct t_stuff {
      t_stuff_gef gef;
    };
    void test2(t_stuff *stuff);
}

int main()
{
    t_stuff stuff;

    strcpy_s(stuff.gef.name, sizeof(stuff.gef.name), "Teststuff");
    stuff.gef.extra = 100.0;

    test2(&stuff);
}

Fortran Code:

module ftncode_mod
   use, intrinsic :: iso_c_binding
   implicit none

   type, public :: t_stuff_gef_ext
     character(1)   :: name(256)
     real(8)        :: extra
   end type t_stuff_gef_ext

   type, public :: t_stuff_ext
     type(t_stuff_gef_ext) :: gef
   end type t_stuff_ext

    contains
      subroutine test2(stuff_ext) bind(C)
      !DEC$ATTRIBUTES DLLEXPORT :: test2
        type(t_stuff_ext), target , intent(in) :: stuff_ext
        continue       
        return
      end

end module
  • Related