将标量和数组元素传递给期望数组的过程 [英] Passing scalars and array elements to a procedure expecting an array

查看:921
本文介绍了将标量和数组元素传递给期望数组的过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些遗留的Fortran 77代码,我试图至少编译没有警告(不禁用警告)。有子例程调用传递一个标量,子例程需要一个数组,因为标量被用作大小为1的数组,所以这不会引起任何问题。但是对于英特尔编译器,如果我启用接口警告,则会收到错误

 错误#8284 :如果实际参数是标量,那么伪参数应该是标量,除非实际参数是字符类型,或者是不是假定形状,指针或多态的数组的元素。 

在某些情况下,我试图通过重载带有数组和标量变量的子例程来解决此问题,但是当传递的参数是数组的一个元素时,我会遇到一个问题,该数组被检测为标量。考虑下面的例子(用gfortran测试):

pre $ $ $ $ $ $ $ $ $ $ $ $ $ b接口readn
子程序readn_s(n,m)
整数m,n
结束子程序
子程序readn_a(n,m)
整数m,n(*)
结束子程序
结束接口
调用readn(n,1)
写(6,*)'n =',n
调用readn(dum,3)
write(6,*)'dum =',dum
call readn(dum(2),2)
write(6,*)'dum =',dum
结束程序

子程序readn_s(n,m)
整数i,m,n
n = 2
结束子程序

子程序readn_a( n,m)
整数i,m,n(*)
do i = 1,m
n(i)= 1
end do
结束子程序



readn(dum,3)调用正确使用 readn_a ,而第二个使用 readn_s 。预期的行为是两者都应该使用 readn_a 。事实上,如果我用 readn_a 替换了这两个调用,一切都如预期的那样。



是否有可能正常工作并且当实际参数是数组元素时,使用重载例程的数组版本?如果我用 readn(dum(2 :),2)调用子例程,我发现它可以工作,但是恐怕会创建一个数组的临时副本...

原始问题:



.f90

 程序a 
整数n,dum(3)
调用readn_a(n,1)
write(6,*)'n = ',n
调用readn_a(dum,3)
write(6,*)'dum =',dum
dum = 3
调用readn_a(dum(2),2 )
write(6,*)'dum =',dum
end program

file2.f90

 子程序readn_a(n,m)
整数i,m,n(*)
do i = 1,m
n(i)= 1
end do
结束子程序

编译 gfortran -Wall file.f90 file2.f90 ifort file.f90 file2.f90 ,一切正常,输出结果如下:

  n = 1 
dum = 1 1 1
dum = 3 1 1

编译 ifort - 获取所有file.f90 file2.f90 ,并且获取错误#8284 以上。所以这就是为什么我想要一个可以与标量或数组一起工作的子程序的一个版本......但是会给数组赋予一个数组元素。

解决方案

在您尝试的解决方案中,type-kind-rank通用解析会将所有数组元素委托给子例程的标量版本,并且不会完成数组部分的预期工作。所以预期的行为是两个都应该使用readn_a。对于您选择的方法来说并不是真的可行。



好吧,这是可能的当你重写代码来传递你自己记下的数组部分时。但是我们再次遇到了和以前一样的问题,你的例子被简化了。我们可以肯定,在你展示的例子中没有临时数组,我们绝对不能说你的真实代码。如果您在某个随机地点开始使用某些2D小节,您肯定会有临时数组,并且可能很难做出正确的小节。



原始警告在原有的遗留代码中应该很容易避免。 FORTRAN 77没有非连续的数组,所以如果你保持你的参数为 integer :: a(*)而不是 integer :: a 并通过进一步。如果您的原始变量是标量,那是一个问题。






问题是整数标量不构成元素序列


F2008 12.5.2.11 1实际参数代表元素序列如果
是一个数组表达式,一个数组元素指示符,一个默认的
字符标量,或者一个带有C字符的类型字符标量
kind(15.2。 2)。 ...

数组元素指示符 a(2)是一个元素但是标量 n 不是。

所以不允许使用序列关联元素被传递:


F2008 12.5.2.11 4表示元素
序列的实际参数 并且对应于伪参数,如果伪参数是
是显式形状或假定大小的数组,则为数组是
序列。 ...

您的代码并不严格符合Fortran规范,但如果您设法编译它,很可能按预期工作。 / p>




可能的解决方案:


  • 您可以将参数作为数组表达式传递,但参数可能不会在子例程内被修改

    call readn_a([n],1)


  • 您可以禁用关于界面匹配的警告。
    $ b

    ifort -warn nointerfaces


  • 您可以创建单独的子例程只能用于标量并以不同的名称进行调用。

  • 您还可以通过英特尔编译器指令禁用参数检查。



    !DEC $ ATTRIBUTES NO_ARG_CHECK :: dummy-arg-name


>

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.

解决方案

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

这篇关于将标量和数组元素传递给期望数组的过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆