如何用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
相关产品推荐
相关产品推荐

