簡體   English   中英

C++和Fortran共享數據結構,C++這邊好,Fortran這邊不好

[英]Shared data structure between C++ and Fortran, good on C++ side, bad on Fortran side

我正在嘗試將結構“stuff”從 C++ 傳遞到 Fortran。“stuff”有一個成員“gef”,其中包含兩個變量“name”和“extra”。 在調用 Fortran 例程 test2 之前,stuff.gef 和 stuff_gef 都是好的,但是當我進入 Fortran 時,“name”和“extra”變量是壞的。

更新:原來的問題已經解決,但是我被推薦在 Fortran 結構上使用 BIND(C)。 我試過了,但出現編譯錯誤,因為 BIND(C) 限定符不允許使用指針。 我需要指針變量指向 map 外部 (_ext) Fortran 結構指向 C++ 結構,因為內部版本具有可分配的 arrays,它不與 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) 限定符的情況下有效。

下面的代碼做你想要的。 重點是將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  

我的解決方案。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM