C++和Fortran之间共享数据结构,C++端较好,Fortran端较差

iezvtpos  于 2023-01-28  发布在  其他
关注(0)|答案(2)|浏览(115)

我试图将结构"stuff"从C传递到Fortran。"stuff"有一个成员"gef",它包含两个变量"name"和"extra"。在调用Fortran例程test2之前,stuff. gef和stuff_gef都是好的,但当我进入Fortran时,"name"和"extra"变量是坏的。
更新:原来的问题解决了,但是我被推荐在Fortran结构上使用BIND(C)。我尝试了但是得到了一个编译错误,因为指针不允许与BIND(C)限定符一起使用。我需要指针变量来将外部(_ext)Fortran结构Map到C
结构,因为内部版本具有不能与C互操作的可分配数组
C
代码:

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

using namespace std;

extern "C" {
    struct t_stuff_gef {
      char   name[256];
      double extra;
      double* p_var;
    };
    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;
    stuff.gef.p_var = new double[2];
    stuff.gef.p_var[0] = 123.0;
    stuff.gef.p_var[1] = 456.0;
    test2(&stuff);
}

Fortran代码:

module ftncode_mod
   use, intrinsic :: iso_c_binding
   implicit none

!--external structure, same as C
   type, public :: t_stuff_gef_ext
     character(1)     :: name(256)
     real(8)          :: extra
     real(8), pointer :: var
   end type t_stuff_gef_ext

!--internal structure, to be be populated from the interface structure above
   type, public :: t_stuff_gef
     character(1)         :: name(256)
     real(8)              :: extra
     real(8), allocatable :: var(:)
   end type t_stuff_gef

   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
        type(t_stuff_gef) :: stuff_gef
        integer :: i
        real(8) :: k
        pointer (p_k,k)
        p_k = loc(stuff_ext%gef%var)
        allocate(stuff_gef%var(2))
        do i = 1, 2
          stuff_gef%var(i) = k
          p_k = p_k + sizeof(k)
        enddo

        print *, stuff_gef%var(1)
        print *, stuff_gef%var(2)

        return
      end

end module

这段代码可以工作,但不需要BIND(C)限定符。

yvfmudvl

yvfmudvl1#

下面的代码做了你想做的事情。重点是将Fortran类型绑定到C,并且当在C端声明指针时声明一个c_ptr

#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

编制:

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

 Teststuff
   100.00000000000000
umuewwlo

umuewwlo2#

我的解决方案。
C++代码:

#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代码:

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

相关问题