如何将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 } } }
关键注意事项
- 必须用
bind(C)显式绑定Fortran和C函数的名称,避免编译器名称修饰导致的链接错误。 - 所有类型必须对应:Fortran的
c_double对应C的double,c_int对应C的int32_t(或int,但int32_t更安全)。 - 不要在C端释放Fortran分配的内存,否则会导致内存泄漏或崩溃。
内容的提问来源于stack exchange,提问作者CuriousAlpaca
相关产品推荐
相关产品推荐

