问题
I am trying to pass the name of another subroutine_b and an array to a generic subroutine_a. This subroutine_a is supposed to pass the array to subroutine_b and get back its computed value.
Following is the code that I have written:
module pass_subroutine_mod1
implicit none
private
public :: ave_value, fx
contains
subroutine ave_value( func, x, y, ave )
! Calculate average of y which is passed on from another function `func`.
!
external :: func
double precision, intent(in), dimension(:) :: x
double precision, intent(inout), dimension(:) :: y
double precision, intent(inout) :: ave
integer :: n
N = size( x )
call func( x, y )
ave = sum( y ) / dble( N )
return
end subroutine ave_value
subroutine fx( x, y )
double precision, dimension(:), intent(in) :: x
double precision, dimension(:), intent(inout) :: y
y = x ** 3
return
end subroutine fx
end module pass_subroutine_mod1
program main
use :: pass_subroutine_mod1
implicit none
integer :: i, N = 101
double precision :: ave
double precision, allocatable, dimension(:) :: x, y
allocate( x(N), y(N), source=0.0d0 )
do i = 1, N
x(i) = dble( i - 1 )
end do
call ave_value( fx, x, y, ave )
write( *, '(A, ES15.6E3)' ) "Average value of y (from fx) = ", ave
deallocate( x, y )
end program main
Here ave_value()
is the subroutine_a and fx()
is subroutine_b.
When I compile and run the above code, it throws the following error:
At line 28 of file pass_subroutine.f90
Fortran runtime error: Array bound mismatch for dimension 1 of array 'y' (1/1125899906842625)
Line 28
is the line y = x ** 3
in subroutine fx( x, y )
.
It thus seems that the arrays x
and y
are not properly passed to fx()
because when I try to print x
from within fx()
, it is unable to do so.
If, instead of arrays x
and y
, I use scalars (and update the code accordingly) the code is able to run properly and output the desired result.
Additionally, after going through this thread, if I modify the ave_value
by adding an interface block, the code runs properly again. Following is the modification with ave_value
:
subroutine ave_value( func, x, y, ave )
! Calculate average of y which is passed on from another function `func`.
!
external :: func
double precision, intent(in), dimension(:) :: x
double precision, intent(inout), dimension(:) :: y
double precision, intent(inout) :: ave
integer :: n
interface
subroutine func( ip, op )
double precision, dimension(:), intent(in) :: ip
double precision, dimension(:), intent(inout) :: op
end subroutine func
end interface
N = size( x )
call func( x, y )
ave = sum( y ) / dble( N )
return
end subroutine ave_value
Thus, my questions are:
a) Is the above modification correct?
b) If yes, then why do I need an interface block when working with arrays and not when working with scalars?
回答1:
It's the assumed-shape array dummy arguments dimension(:)
that require an explicit interface. This is because the compiler has to do something different for these, typically passing a descriptor. It doesn't matter what's on the calling side, it's the dummy arguments of the called procedure that matter.
For more information see my old blog post Doctor Fortran Gets Explicit - Again!
You may want to look at the language feature abstract interface
, along with procedure
, to make the code look a bit cleaner.
回答2:
When you have a dummy procedure argument, as func
in ave_value
is, there is no "assumed interface". While the array dummy arguments x
and y
are assumed-shape (they take their shape from the actual argument when the procedure is invoked) there's nothing similar for procedures.
Instead, the procedure func
has the interface it's declared with. In this case, you have the declaration
external :: func
so that func
is an external procedure with implicit interface. As we know, an implicit interface is not suitable when we want to reference it and it has assumed-shape array arguments ip
and op
.
You need somehow to explicitly give the dummy argument the correct interface. One way, as you've seen, is to use an interface block to give the external procedure an explicit interface. Alternatively, you can use a procedure declaration statement like
procedure(iface) func
where iface
is an appropriate interface. There are several ways to make that interface available, but I won't go into them here.
来源:https://stackoverflow.com/questions/57579287/how-to-pass-array-to-a-procedure-which-is-passed-as-an-argument-to-another-proce