C++与Fortran共享数据结构:添加可分配数组遇编译错误求助
解决Fortran与C++互操作中带BIND(C)属性结构体的编译错误
问题背景
在C向Fortran传递字符、double类型及动态数组的场景中,Fortran侧需定义两类结构体:一类用于与C互操作,另一类包含可分配数组用于内部处理。原本通过数据复制的方案可正常运行,但为外部互操作结构体t_stuff_gef_ext添加BIND(C)属性后,触发编译错误:
error #8080: Each component of a derived type with the BIND attribute shall be a nonpointer, nonallocatable data component with interoperable type and type parameters. [P_VAR]
错误原因
Fortran标准明确规定:带BIND(C)属性的派生类型,所有成员必须是非指针、非可分配的互操作兼容类型。原代码中t_stuff_gef_ext的real(8), pointer :: var是Fortran原生指针,不符合互操作要求——C语言的指针在Fortran互操作中需用type(c_ptr)类型表示。
修正方案
关键改动点
- 外部互操作结构体添加
BIND(C)属性,成员替换为互兼容类型:- 字符数组改用
character(c_char)(对应C的char) - 指针成员改用
type(c_ptr)(对应C的double*)
- 字符数组改用
- 使用标准库函数
c_f_pointer将C指针转换为Fortran可关联的指针,替代手动地址操作,更安全规范。
修正后的Fortran代码
module ftncode_mod use, intrinsic :: iso_c_binding implicit none !--external structure with BIND(C) for C++ interoperability type, public, bind(C) :: t_stuff_gef_ext character(c_char) :: name(256) ! 对应C的char[256] real(c_double) :: extra ! 对应C的double type(c_ptr) :: p_var ! 对应C的double* end type t_stuff_gef_ext !--internal structure with allocatable array for processing type, public :: t_stuff_gef character(c_char) :: name(256) real(c_double) :: extra real(c_double), allocatable :: var(:) end type t_stuff_gef 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 type(t_stuff_ext), intent(in) :: stuff_ext type(t_stuff_gef) :: stuff_gef real(c_double), pointer :: var_ptr(:) ! Fortran指针用于关联C数组 integer :: i ! 将C指针转换为Fortran数组指针(指定数组长度为2) call c_f_pointer(stuff_ext%gef%p_var, var_ptr, [2]) ! 复制数据到内部可分配数组 allocate(stuff_gef%var(2)) stuff_gef%var = var_ptr stuff_gef%name = stuff_ext%gef%name stuff_gef%extra = stuff_ext%gef%extra ! 输出验证 print *, stuff_gef%var(1) print *, stuff_gef%var(2) end subroutine test2 end module
C++代码(无需修改,补充内存释放)
#include <iostream> #include <cstddef> #include <cstring> 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); // 释放动态分配的内存 delete[] stuff.gef.p_var; return 0; }
说明
修正后的代码完全符合Fortran与C互操作的规范,既消除了编译错误,又实现了将C++传递的动态数组数据复制到Fortran内部可分配数组的需求。使用c_f_pointer是标准的指针转换方式,比手动操作内存地址更可靠。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

