我遇到了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
答案 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
的声明,并为f1
和f2
添加过程声明,如下所示:
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数组时,你正在使用一维数组。