用于不匹配数组维度的Fortran子程序指针

时间:2012-03-16 19:41:19

标签: arrays pointers fortran subroutine dimension

我遇到了Fortran和函数/子例程指针的问题。我有两个函数将数组作为参数。在f1中它是(n,n),在f2中它是a(n * n)。当我手动调用子程序时,我可以使用相同的数组执行此操作:

real :: a(5, 5)
call f1(a, 5)
call f2(a, 5)

但是当我尝试使用指针执行此操作时,编译器会将此错误抛回给我:

ptr => f2
       1
Error: Interface mismatch in procedure pointer assignment at (1): Type/rank missmatch in argument 'a'

有解决方法吗?我在考虑指针,但我有同样的问题,要创建它我需要知道尺寸的数量。

供参考,这是完整的代码(我希望它不会太长......)

program ptrtest
implicit none

interface
    subroutine fnc(a, n)
        integer :: n
        real :: a(n, n)
    end subroutine

    subroutine f1(a, n)
        integer :: n
        real :: a(n, n)
    end subroutine

    subroutine f2(a, n)
        integer :: n

        real :: a(n*n)
    end subroutine
end interface

procedure(fnc), pointer :: ptr => null()
real :: a(5, 5)
real :: b(4, 4)

ptr => f1

call ptr(a, 5)
write(*,*) a

!this one does not work..

!ptr => f2
!
!call ptr(b, 4)
!write(*,*) b

call f2(b, 4)
write(*,*) b
end program

subroutine f1(a, n)
integer :: n
real :: a(n, n)
integer :: i

a = 1
end subroutine

subroutine f2(a, n)
integer :: n
real :: a(n*n)

a = 2
end subroutine

我真的希望有办法做到这一点。我无法真正重写所有子程序,因此每次都会匹配数组的尺寸:/

问候,Caba

4 个答案:

答案 0 :(得分:2)

编辑:正如在其他答案中所写的那样,实际和虚拟参数不匹配。而不是试图解决我的建议是创建一个指针,转换数组的等级,以便参数匹配。该技术是“指针边界重新映射”(也见changing array dimensions in fortran。)这是一个更完整的例子:

module my_subs

contains

subroutine f1 (array)

   real, dimension (:,:), intent (in) :: array
   write (*, *) "f1:", ubound (array, 1), ubound (array, 2)

end subroutine f1


subroutine f2 (array)

   real, dimension (:), intent (in) :: array
   write (*, *) "f2:", ubound (array, 1)

end subroutine f2

end module my_subs


program test_ranks

   use my_subs
   real, dimension (2,2), target :: a2d
   real, dimension (:), pointer :: a4

   a2d = reshape ( [1., 2., 3., 4.], [2,2] )
   call f1 (a2d)

   a4 (1:4) => a2d
   call f2 (a4)

end program test_ranks

我在模块中有子程序自动使接口显式化 - 我认为这是最安全的做法,因为它允许编译器找到参数一致性错误,并且对于“高级”Fortran 90功能是必要的,例如假设 - 我使用的形状尺寸(冒号)。

也许这个例子不符合问题的需要,因为它没有使用指向程序的指针。它确实将相同的数组传递给期望不同等级数组的过程。

答案 1 :(得分:2)

您正在将2D数组(:,:)传递给需要1D(:)数组的子例程。这就是Fortran抱怨的原因。解决这个问题的一种方法是编写一个具有多个函数的模块,这些函数具有相同的名称,将不同的秩数组作为参数,如下所示:

  module test 

  interface fnc1
      module procedure fnc1_1d, fnc1_2d
  end interface

  contains

  subroutine fnc1_1d(ar,b,ar_out)

  real :: ar(:), ar_out(:)
  integer :: b

  ar_out = ar*b

  end subroutine fnc1_1d

  subroutine fnc1_2d(ar,b,ar_out)

  real :: ar(:,:), ar_out(:,:)
  integer :: b

  ar_out = ar*b

  end subroutine fnc1_2d

  end module test

现在当你调用fnc1时,如果你传递一维数组,它将调用fnc1_1d,如果你传递一个二维数组,它将调用fnc_2d。

Program modify_value

use test

implicit none

real :: a1(5), a1_out(5)
real :: a2(5,5), a2_out(5,5)
integer :: j

a1 = 1.
a2 = 2.

call fnc1(a1,4,a1_out)
call fnc1(a2,4,a2_out)

open(1,file="out.txt")

write(1,'(5F5.1)') a1_out
do j=1,5
    write(1,'(5F5.1)') a2_out(j,:)
end do


close(1)

End Program
out.txt中的

现在是:

4.0 4.0 4.0 4.0 4.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

希望这有帮助。

答案 2 :(得分:2)

如果我将示例程序从使用显式接口(通过接口块)更改为使用隐式接口(通过过程声明而不提及接口),它似乎对我有效。

因此,删除接口块,略微更改ptr的声明,并为f1f2添加过程声明,如下所示:

procedure(), pointer :: ptr => null()
procedure() :: f1, f2

(或者,您可以使用external的{​​{1}}语句和f1,而不是过程语句。)

我不知道这对于真正的程序有多可行,因为如果实际的子程序使用Fortran 90及更高版本中引入的一些功能,则可能需要显式接口。

答案 3 :(得分:0)

在本节中:

子程序f2(a,n)integer :: n real :: a(n * n)

当fortran在主程序中需要2D数组时,你正在使用一维数组。