如何为'allocate'编写包装器

时间:2010-02-13 11:03:56

标签: fortran

我正在尝试为'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)  

有没有办法实现这样的包装?

谢谢!

2 个答案:

答案 0 :(得分:11)

这可以通过通用接口块完成。您必须为要处理的每个等级创建过程,例如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

答案 1 :(得分:1)

subroutine memory(array, length)第一个虚拟参数 1维数组real(8), allocatable, intent(out), dimension(:) :: array)。

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

如果你真的需要这样的子程序,为每个不同维度的数组写一对memory / freem子程序 - 一个子程序对用于一维数组,另一个用于二维数组,等等。 / p>

顺便说一句,memory子程序通常会有所不同,因为为了分配n维数组,你需要将n个范围传递给上面提到的子程序。