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

如何将Fortran可分配多维数组传递给C函数并修改?

问题解答

你的当前写法无法实现,直接将Fortran二维可分配数组传给C的double**参数会导致内存访问错误,核心原因是两者的内存布局完全不兼容:

  • Fortran多维数组(包括可分配数组)采用列优先连续存储,整个数组是一块连续的内存块,没有行指针数组。
  • C的double**是指向指针数组的指针,每个元素指向一行的起始地址,属于非连续的间接布局。

下面提供两种不需要扁平化数组的标准兼容解决方案:


方案1:传递连续内存指针+维度信息(推荐,跨编译器兼容)

这种方法利用Fortran多维数组的连续内存特性,直接传递数组首地址给C的double*,同时传递数组的行数和列数,C端通过计算偏移访问元素。

Fortran端代码修改

program test
use iso_c_binding
implicit none

! 必须显式声明C函数的接口块
interface
    subroutine c_func(arr, rows, cols) bind(C, name='c_func')
        import :: c_double, c_int
        real(c_double), intent(inout) :: arr(rows, cols)  ! 假定形状数组,关联到连续内存
        integer(c_int), intent(in), value :: rows, cols    ! 用value属性传递整数,匹配C的传值
    end subroutine c_func
end interface

real(c_double), dimension(:,:), allocatable :: a

allocate(a(2,3))
! 初始化数组方便验证修改效果
a = reshape([1.0d0,2.0d0,3.0d0,4.0d0,5.0d0,6.0d0], [2,3])

! 传递数组、行数、列数
call c_func(a, int(size(a,1), c_int), int(size(a,2), c_int))

print *, "Modified array:"
print *, a

end program test

C端代码实现

#include <stdint.h>  // 用int32_t匹配Fortran的c_int,避免平台位数差异

void c_func(double *arr, int32_t rows, int32_t cols) {
    // Fortran列优先存储,索引公式:arr[i + j*rows] 对应 Fortran的a(i+1, j+1)
    // (C是0索引,Fortran是1索引)
    int32_t i, j;
    for (j = 0; j < cols; j++) {
        for (i = 0; i < rows; i++) {
            arr[i + j*rows] *= 2.0;  // 示例:每个元素乘2
        }
    }
}

方案2:手动构建指针数组模拟二维指针

如果一定要用C的double**接口,可以在Fortran端手动创建一个指针数组,指向二维数组的每一列(因为Fortran是列优先,每列是连续的),再传递给C。

Fortran端代码修改

program test
use iso_c_binding
implicit none

interface
    subroutine c_func(arr_ptr, rows, cols) bind(C, name='c_func')
        import :: c_double, c_int, c_ptr
        type(c_ptr), intent(inout) :: arr_ptr(cols)  ! 指向每一列的指针数组
        integer(c_int), intent(in), value :: rows, cols
    end subroutine c_func
end interface

real(c_double), dimension(:,:), allocatable :: a
type(c_ptr), dimension(:), allocatable :: a_ptr
integer(c_int) :: rows, cols, j

allocate(a(2,3))
a = reshape([1.0d0,2.0d0,3.0d0,4.0d0,5.0d0,6.0d0], [2,3])
rows = int(size(a,1), c_int)
cols = int(size(a,2), c_int)
allocate(a_ptr(cols))

! 给每个列绑定指针
do j = 1, cols
    a_ptr(j) = c_loc(a(1,j))
end do

call c_func(a_ptr, rows, cols)

print *, "Modified array:"
print *, a

deallocate(a_ptr, a)
end program test

C端代码实现

#include <stdint.h>

void c_func(double **arr_ptr, int32_t rows, int32_t cols) {
    // arr_ptr[j] 指向第j列的首地址,arr_ptr[j][i] 对应 Fortran的a(i+1, j+1)
    int32_t i, j;
    for (j = 0; j < cols; j++) {
        for (i = 0; i < rows; i++) {
            arr_ptr[j][i] += 10.0;  // 示例:每个元素加10
        }
    }
}

关键注意事项

  1. 必须用bind(C)显式绑定Fortran和C函数的名称,避免编译器名称修饰导致的链接错误。
  2. 所有类型必须对应:Fortran的c_double对应C的double,c_int对应C的int32_t(或int,但int32_t更安全)。
  3. 不要在C端释放Fortran分配的内存,否则会导致内存泄漏或崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 20:42:14