![](/img/trans.png)
[英]Shared data structure between C++ and Fortran: adding allocatable arrays
[英]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.