Passing scalars and array elements to a procedure expecting an array

两盒软妹~` 提交于 2019-12-04 04:57:14

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!