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

如何用C调用含编译期未知大小数组的Fortran派生类型程序?

Fortran参数化派生类型与C互操作的问题解答

1. 参数化派生类型无法直接被C调用

你当前代码中尝试使用带长度参数的参数化派生类型并添加bind(c),这种方案不能被C直接调用,原因如下:

  • C语言没有参数化类型的概念,无法识别依赖外部参数n的results(n)类型,也无法声明对应的结构体。
  • Fortran标准中,带bind(c)的类型必须是与C兼容的互操作类型,而长度参数化的派生类型不符合C的固定布局要求——C的结构体成员大小必须是编译期确定的固定值,不能依赖运行期或外部参数。
  • 多数Fortran编译器会直接报错(例如GCC提示“Parameterized derived type with BIND(C) is not allowed”),因为这种类型无法与C类型系统兼容。

2. 更优实现:C风格动态数组结构体

改用包含数组长度和C指针的bind(c)派生类型,结合Fortran的c_ptr和c_f_pointer实现互操作,这是C/Fortran交互中处理动态数组的标准方案:

Fortran端代码

module dt
    use iso_c_binding
    implicit none

    ! 与C兼容的固定布局结构体
    type, bind(c) :: results
        integer(c_int) :: n               ! 数组长度
        type(c_ptr) :: myarray_ptr        ! 指向double数组的C指针
    end type results

contains

    ! 填充结果的子例程(C可调用)
    subroutine set_results(res, n) bind(c, name='set_results')
        type(results), intent(out) :: res
        integer(c_int), intent(in) :: n
        real(c_double), pointer :: myarray(:)
        integer(c_int) :: i

        ! 动态分配Fortran数组
        allocate(myarray(n))
        do i = 1, n
            myarray(i) = real(i, c_double)
        end do

        ! 将Fortran数组转换为C指针存入结构体
        res%n = n
        res%myarray_ptr = c_loc(myarray)
    end subroutine set_results

    ! 释放内存的子例程(必须调用避免泄漏)
    subroutine free_results(res) bind(c, name='free_results')
        type(results), intent(inout) :: res
        real(c_double), pointer :: myarray(:)

        if (c_associated(res%myarray_ptr)) then
            call c_f_pointer(res%myarray_ptr, myarray, [res%n])
            deallocate(myarray)
            res%myarray_ptr = c_null_ptr
            res%n = 0
        end if
    end subroutine free_results

end module dt

C端调用代码

#include <stdio.h>

// 与Fortran结构体一一对应的C结构体声明
typedef struct {
    int n;
    double *myarray_ptr;
} results;

// 声明Fortran导出的子程序
void set_results(results *res, int n);
void free_results(results *res);

int main() {
    results res;
    int i;

    set_results(&res, 10);
    printf("Array elements:\n");
    for (i = 0; i < res.n; i++) {
        printf("%.1f ", res.myarray_ptr[i]);
    }
    printf("\n");

    // 必须调用释放函数回收内存
    free_results(&res);
    return 0;
}

3. 可以实现为函数而非子例程

Fortran支持返回bind(c)派生类型的函数,C端可以直接接收这种返回值,只需注意内存管理:

Fortran函数版本

module dt
    use iso_c_binding
    implicit none

    type, bind(c) :: results
        integer(c_int) :: n
        type(c_ptr) :: myarray_ptr
    end type results

contains

    ! 返回results类型的函数(C可调用)
    function create_results(n) bind(c, name='create_results') result(res)
        integer(c_int), intent(in) :: n
        type(results) :: res
        real(c_double), pointer :: myarray(:)
        integer(c_int) :: i

        allocate(myarray(n))
        do i = 1, n
            myarray(i) = real(i, c_double)
        end do

        res%n = n
        res%myarray_ptr = c_loc(myarray)
    end function create_results

    ! 同前:内存释放函数
    subroutine free_results(res) bind(c, name='free_results')
        type(results), intent(inout) :: res
        real(c_double), pointer :: myarray(:)

        if (c_associated(res%myarray_ptr)) then
            call c_f_pointer(res%myarray_ptr, myarray, [res%n])
            deallocate(myarray)
            res%myarray_ptr = c_null_ptr
            res%n = 0
        end if
    end subroutine free_results

end module dt

C端调用代码

#include <stdio.h>

typedef struct {
    int n;
    double *myarray_ptr;
} results;

results create_results(int n);
void free_results(results *res);

int main() {
    results res = create_results(10);
    int i;

    printf("Array elements:\n");
    for (i = 0; i < res.n; i++) {
        printf("%.1f ", res.myarray_ptr[i]);
    }
    printf("\n");

    free_results(&res);
    return 0;
}

内容的提问来源于stack exchange,提问作者David Wallis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:55:20