问题
I have some legacy Fortran 77 code which I'm trying to at least compile without warnings (without disabling warnings). There are subroutine calls that pass a scalar where subroutine expects an array, since the scalar is used as a size-1 array, this causes no problems. But with the Intel compiler, if I enable interface warnings I get this error:
error #8284: If the actual argument is scalar, the dummy argument shall be scalar unless the actual argument is of type character or is an element of an array that is not assumed shape, pointer, or polymorphic.
In some cases, I've tried to solve this by overloading the subroutine with array and scalar variants, but then I face a problem when the argument passed is an "an element of an array", which is detected as a scalar. Consider the following sample (tested with gfortran):
program a
integer n,dum(3)
interface readn
subroutine readn_s(n,m)
integer m,n
end subroutine
subroutine readn_a(n,m)
integer m,n(*)
end subroutine
end interface
call readn(n,1)
write(6,*) 'n=',n
call readn(dum,3)
write(6,*) 'dum=',dum
call readn(dum(2),2)
write(6,*) 'dum=',dum
end program
subroutine readn_s(n,m)
integer i,m,n
n=2
end subroutine
subroutine readn_a(n,m)
integer i,m,n(*)
do i=1,m
n(i)=1
end do
end subroutine
The readn(dum,3)
call correctly uses readn_a
, while the second one uses readn_s
. The intended behaviour is that both should use readn_a
. Indeed, if I replace both calls with readn_a
everything is as expected.
Is it possible to have this working properly and use the "array" version of the overloaded routine when the actual argument is an array element? I've found out it works if I call the subroutine with readn(dum(2:),2)
, but I'm afraid that creates a temporary copy of the array...
Original problem:
file.f90
program a
integer n,dum(3)
call readn_a(n,1)
write(6,*) 'n=',n
call readn_a(dum,3)
write(6,*) 'dum=',dum
dum=3
call readn_a(dum(2),2)
write(6,*) 'dum=',dum
end program
file2.f90
subroutine readn_a(n,m)
integer i,m,n(*)
do i=1,m
n(i)=1
end do
end subroutine
Compile with gfortran -Wall file.f90 file2.f90
or ifort file.f90 file2.f90
, all is fine and the output is the intended:
n= 1
dum= 1 1 1
dum= 3 1 1
Compile with ifort -warn all file.f90 file2.f90
and I get the error #8284
above. So that's why I wanted a version of the subroutine that would work with scalars or arrays... but would give the array version with an array element.
回答1:
In your attempted solution the type-kind-rank generic resolution will delegate all array elements to the scalar version of the subroutine and that will not do the intended work on the part of the array. So "The intended behaviour is that both should use readn_a." is not really possible with the approach you chose.
Well, it is possible when you rewrite the code to pass array sections as you noted yourself. But we are again at the same problem as we were before, you example is simplified. We can be certain there there is no temporary array in the example you have shown, we definitely can't say that about your real code. If you use some 2D subsections starting at some random place, you will have temporary arrays for sure and it might be difficult to make the correct subsection at all.
The original warning should be reasonably easy to avoid in your original legacy code. FORTRAN 77 has no non-contiguous arrays so if you keep your arguments to be integer :: a(*)
instead of integer :: a
and pass that further. If your original variable is scalar, that is a problem.
The problem is that an integer scalar does not constitute an element sequence:
F2008 12.5.2.11 1 An actual argument represents an element sequence if it is an array expression, an array element designator, a default character scalar, or a scalar of type character with the C character kind (15.2.2). ...
An array element designator a(2)
is an element sequence but the scalar n
is not.
So it is not allowed for sequence association which is used when an array element is passed:
F2008 12.5.2.11 4 An actual argument that represents an element sequence and corresponds to a dummy argument that is an array is sequence associated with the dummy argument if the dummy argument is an explicit-shape or assumed-size array. ...
Your code is not strictly standard Fortran conforming, but very likely to work as expected if you manage to compile it.
Possible solutions:
You can pass the argument as an array expression, but the argument may not be modified inside the subroutine
call readn_a([n],1)
You can just disable the warnings about interface matching
ifort -warn nointerfaces
You can create separate subroutines which only work for scalars and call it under some different name.
You can also disable argument checking for that dummy argument by an Intel Compiler directive
!DEC$ ATTRIBUTES NO_ARG_CHECK :: dummy-arg-name
来源:https://stackoverflow.com/questions/41630361/passing-scalars-and-array-elements-to-a-procedure-expecting-an-array