How to allocate an array inside fortran routine “called” from C

前端 未结 3 622
刺人心
刺人心 2020-12-21 04:09

I think title says what I need. I know we can use \"asd\" function to do this, but for some reasons I need to do the allocation in Fortran (i.e. in subroutine \"asd_\"). Her

3条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-21 05:01

    If you need a thread safe solution and/or the possibility to deallocate the space from C again, the example below would do the job:

    #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;
    }
    

    On the Fortran side, you have a general wrapper type CWrapper, which can carry any type of derived type. Latter contains the data you would like to pass around. The CWrapper type accept arbitrary payload, and you would always invoke the free_wrapper() routine from C to release the memory.

    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
    

提交回复
热议问题