2

我遇到了 Fortran 和函数/子例程指针的问题。我有两个将数组作为参数的函数。在 f1 中是 a(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

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

问候, 卡巴

4

4 回答 4

2

编辑:关键是,正如在其他答案中所写,实际参数和虚拟参数不匹配。与其尝试解决我的建议,不如创建一个指针来转换数组的等级以使参数匹配。该技术是“指针边界重新映射”(另请参见更改 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 特性是必要的,例如假定形状尺寸(冒号)我使用的。

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

于 2012-03-16T23:20:45.303 回答
2

您将二维数组 (:,:) 传递给需要一维 (:) 数组的子例程。这就是 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

希望这可以帮助。

于 2012-03-16T23:23:04.373 回答
2

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

所以删除接口块,稍微修改 的声明,并为andptr添加过程声明,如下所示:f1f2

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

(或者,您可以使用externalforf1和的语句来f2代替过程语句。)

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

于 2012-03-16T23:51:06.187 回答
0

在这个部分:

子程序 f2(a, n) 整数 :: n 实数 :: a(n*n)

当 fortran 在主程序中需要一个二维数组时,您正在使用一维数组。

于 2012-03-16T23:33:11.283 回答