如何在C语言中“调用”fortran例程中分配一个数组

我认为头衔说我需要什么。 我知道我们可以使用“asd”函数来执行此操作,但由于某些原因,我需要在Fortran中进行分配(即在子例程“asd_”中)。 这是C代码:

#include  void asd(float **c) { *c = (float *) malloc (2*sizeof(float)); **c =123; *(*c+1)=1234; } void asd_(float **c); main () { float *c; asd_(&c); // asd(&c); would do the job perfectly printf("%f %f \n",c[0],c[1]); return 0; } 

这是Fortran代码:

  subroutine asd(c) implicit none real, pointer, allocatable ::c(:) print *, associated(c) if(.not. associated(c)) allocate(c(2)) end subroutine 

这随机给出了分段错误。 任何帮助,将不胜感激。

Fortran 2003 ISO C Binding提供了一种可移植的方法。 它在许多编译器中实现。 这是示例代码。

 #include  void test_mem_alloc ( float ** array ); int main ( void ) { float * array; test_mem_alloc (&array); printf ( "Values are: %f %f\n", array [0], array [1] ); return 0; } 

 subroutine test_mem_alloc ( c_array_ptr ) bind (C, name="test_mem_alloc") use, intrinsic :: iso_c_binding implicit none type (c_ptr), intent (out) :: c_array_ptr real (c_float), allocatable, dimension (:), target, save :: FortArray allocate (FortArray (1:2) ) FortArray = [ 2.5_c_float, 4.4_c_float ] c_array_ptr = c_loc (FortArray) end subroutine test_mem_alloc 

如果您想使用Fortran内部类型,这也是另一种解决方案。 这是我的情况,因为我需要使用预先指定的数据类型从外部库调用例程。 这基本上是使用包装器Fortran子例程完成的。 这是C代码:

 void mywrap_(void **); void myprint_(void *); main () { void *d; mywrap_(&d); myprint_(d); return 0; } 

这是包装器:

  subroutine mywrap(b) implicit none include "hh" type(st), target, save :: a integer, pointer :: b interface subroutine alloc(a) include "hh" type(st) a end subroutine alloc end interface call alloc(a) b => a%i end 

和Fortran代码:

  subroutine alloc(a) implicit none include "hh" type(st) a a%i = 2 a%r = 1.5 if (allocated(a%s)) deallocate(a%s) allocate(a%s(2)) a%s(1) = 1.23 a%s(2) = 1234 end !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine myprint(a) implicit none include "hh" type(st) a print *,"INT: ", a%i print *,"REAL: ", a%r print *,"ALLOC: ", a%s end 

头文件“hh”:

  type st sequence integer i real r real, allocatable :: s(:) end type 

注意,这样所有对象在C中都是不透明的。

如果您需要一个线程安全的解决方案和/或再次从C释放空间的可能性,下面的示例将完成这项工作:

 #include  void test_mem_alloc(float ** array, void **wrapper); void free_wrapper(void **wrapper); int main() { float *array; void *wrapper; /* Allocates space in Fortran. */ test_mem_alloc(&array, &wrapper); printf( "Values are: %f %f\n", array [0], array [1]); /* Deallocates space allocated in Fortran */ free_wrapper(&wrapper); return 0; } 

在Fortran端,您有一个通用的包装器类型CWrapper ,它可以携带任何类型的派生类型。 Latter包含您想要传递的数据。 CWrapper类型接受任意有效负载,您总是从C调用free_wrapper()例程来释放内存。

 module memalloc use, intrinsic :: iso_c_binding implicit none type :: CWrapper class(*), allocatable :: data end type CWrapper type :: CfloatArray real(c_float), allocatable :: array(:) end type CfloatArray contains subroutine test_mem_alloc(c_array_ptr, wrapper_ptr)& & bind(C, name="test_mem_alloc") type (c_ptr), intent (out) :: c_array_ptr type(c_ptr), intent(out) :: wrapper_ptr type(CWrapper), pointer :: wrapper allocate(wrapper) allocate(CfloatArray :: wrapper%data) select type (data => wrapper%data) type is (CfloatArray) allocate(data%array(2)) data%array(:) = [2.5_c_float, 4.4_c_float] c_array_ptr = c_loc(data%array) end select wrapper_ptr = c_loc(wrapper) end subroutine test_mem_alloc subroutine free_cwrapper(wrapper_ptr) bind(C, name='free_wrapper') type(c_ptr), intent(inout) :: wrapper_ptr type(CWrapper), pointer :: wrapper call c_f_pointer(wrapper_ptr, wrapper) deallocate(wrapper) end subroutine free_cwrapper end module memalloc