2010-02-13 76 views
8

我想为'allocate'函数编写一个包装,即接收数组和维度的函数,分配内存并返回分配的数组。最重要的是该函数必须适用于不同级别的数组。但是我必须在函数接口中明确声明数组的等级,并且在这种情况下,如果我将特定等级的数组作为参数传递,则代码仅进行编译。例如,此代码不能编译:如何为'allocate'编写包装

module memory_allocator 
contains 

    subroutine memory(array, length) 
    implicit none 

    real(8), allocatable, intent(out), dimension(:) :: array 
    integer, intent(in) :: length 

    integer :: ierr 

    print *, "memory: before: ", allocated(array) 

    allocate(array(length), stat=ierr) 
    if (ierr /= 0) then 
     print *, "error allocating memory: ierr=", ierr 
    end if 

    print *, "memory: after: ", allocated(array) 

    end subroutine memory 

    subroutine freem(array) 
    implicit none 

    real(8), allocatable, dimension(:) :: array 

    print *, "freem: before: ", allocated(array) 
    deallocate(array) 
    print *, "freem: after: ", allocated(array) 

    end subroutine freem 

end module memory_allocator 

program alloc 
    use memory_allocator 
    implicit none 

    integer, parameter :: n = 3 
    real(8), allocatable, dimension(:,:,:) :: foo 
    integer :: i, j, k 

    print *, "main: before memory: ", allocated(foo) 
    call memory(foo, n*n*n) 
    print *, "main: after memory: ", allocated(foo) 

    do i = 1,n 
    do j = 1,n 
     do k = 1, n 
     foo(i, j, k) = real(i*j*k) 
     end do 
    end do 
    end do 

    print *, foo 

    print *, "main: before freem: ", allocated(foo) 
    call freem(foo) 
    print *, "main: after freem: ", allocated(foo) 

end program alloc 

编译错误:

gfortran -o alloc alloc.f90 -std=f2003 
alloc.f90:46.14: 

    call memory(foo, n*n*n) 
       1 
Error: Rank mismatch in argument 'array' at (1) (1 and 3) 
alloc.f90:60.13: 

    call freem(foo) 
      1 
Error: Rank mismatch in argument 'array' at (1) (1 and 3) 

有没有实施这样的包装..

感谢的什么办法?!

回答

10

这可以通过通用接口块来完成。您必须为要处理的每个等级创建过程,例如memory_1d,memory_2d,... memory_4d。 (很明显,很多剪贴&粘贴)。然后你编写一个通用接口块,为所有这些过程提供替代名称内存作为通用过程名称。当你调用内存时,编译器根据参数的等级来区分应该调用哪一个memory_Xd。你的freem函数也一样。

这就是sin这样的内在函数如何长期工作 - 你可以用各种预设的真实论证或者用一个复杂的论证来调用罪,编译器会用实际的sin函数来调用。在真正旧的FORTRAN中,你必须为不同的sin函数使用不同的名称。现在的Fortran你可以用你自己的例程设置相同的东西。

编辑:添加代码示例演示方法&语法:

module double_array_mod 

    implicit none 

    interface double_array 
     module procedure double_vector 
     module procedure double_array_2D 
    end interface double_array 

    private ! hides items not listed on public statement 
    public :: double_array 

contains 

    subroutine double_vector (vector) 
     integer, dimension (:), intent (inout) :: vector 
     vector = 2 * vector 
    end subroutine double_vector 

    subroutine double_array_2D (array) 
     integer, dimension (:,:), intent (inout) :: array 
     array = 2 * array 
    end subroutine double_array_2D 

end module double_array_mod 


program demo_user_generic 

    use double_array_mod 

    implicit none 

    integer, dimension (2) :: A = [1, 2] 
    integer, dimension (2,2) :: B = reshape ([11, 12, 13, 14], [2,2]) 
    integer :: i 

    write (*, '(/ "vector before:",/2(2X, I3))') A 
    call double_array (A) 
    write (*, '(/ "vector after:",/2(2X, I3))') A 

    write (*, '(/ "2D array before:")') 
    do i=1, 2 
     write (*, '(2(2X, I3))') B (i, :) 
    end do 
    call double_array (B) 
    write (*, '(/ "2D array after:")') 
    do i=1, 2 
     write (*, '(2(2X, I3))') B (i, :) 
    end do 

    stop 
end program demo_user_generic 
+0

非常感谢!虽然它需要分配器模块中的代码重复,但至少我可以在调用此分配器函数时使用通用名称。这是我想要的。 – robusta 2010-02-13 21:46:44

1

subroutine memory(array, length)具有第一虚拟参数1维阵列real(8), allocatable, intent(out), dimension(:) :: array)。

从你的主程序中调用这个子程序与三维数组 foo(real(8), allocatable, dimension(:,:,:) :: foo)显然是错误的。这就是编译器实际上所说的。

如果确实需要这样的子程序写入一对memory/freem子程序用于不同尺寸的每个阵列 - 一个子程序对1维阵列,另一个为2维阵列等

顺便提及, memory子例程通常会有所不同,因为为了分配n维数组,您需要将n个扩展块传递给上述子例程。

+0

kemiisto,我明白,这编译错误是绝对明显。我也明白,实现我想要的一种方式是为不同级别编写单独的分配器。我将不得不这样做,作为最后的手段:)但我的问题是 - 是否有一个合法的fortran编写包装分配与SAME功能,即通用Wrt等级的方式... 谢谢! – robusta 2010-02-13 11:53:53