You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)类型表示。

修正方案

关键改动点

  1. 外部互操作结构体添加BIND(C)属性,成员替换为互兼容类型:
    • 字符数组改用character(c_char)(对应C的char)
    • 指针成员改用type(c_ptr)(对应C的double*)
  2. 使用标准库函数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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 13:20:32