接口中数组的形状是否可以匹配多个固定数组大小?

时间:2015-06-03 12:49:20

标签: fortran fortran95

我有多个带有参数p的子程序,它是一个显式大小的数组,如

subroutine foo(p)
integer,dimension(2),intent(in) ::p
end subroutine foo

subroutine bar(p)
integer,dimension(3),intent(in) ::p
end subroutine bar

我想通过间接调用调用这两个函数,但是找不到一种方法来声明一个匹配foo和bar签名的接口......

例如,在接口中使用假定的数组大小不起作用:

subroutine indirect(f,p)
integer,dimension(*),intent(in):p
interface
  subroutine f(p)
  integer,dimension(*),intent(in) :: p
  end subroutine f
end interface
call f(p)
end subroutine indirect

当我通过间接调用foo或bar时,编译器(gfortran 4.9.2)抱怨f的第一个参数p的形状不匹配...

integer,dimension(2) :: pfoo
integer,dimension(3) :: pbar

pfoo = (/ 0,1 /)
pbar = (/ 1,2,3 /)

call foo(pfoo) ! direct call is OK
call bar(pbar)

call indirect(foo,pfoo) ! compiler complains about foo signature
call indirect(bar,pbar) ! same for bar...

编译器错误类似于:

Error: Interface mismatch in dummy procedure 'f' at (1): Shape mismatch in dimension 1 of argument 'p'

当然,我可以修改foo和bar签名以使用假定的数组大小(*)而不是固定的数组大小,但是

  1. 就像我为了制作编译器而丢失了一些信息 很高兴没有添加任何安全性

  2. foo和bar不是我的代码,我宁愿不改变它们......

  3. 我找到了一种解决方法,但它包括为每个子程序foo和bar编写假定大小的包装器

    call indirect(foo_wrapper,pfoo) ! compiler complains about foo signature
    call indirect(bar_wrapper,pbar) ! same for bar...
    
    subroutine foo_wrapper(p)
    integer,dimension(*),intent(in) ::p
    call foo(p)
    end subroutine foo_wrapper
    
    subroutine bar_wrapper(p)
    integer,dimension(*),intent(in) ::p
    call bar(p)
    end subroutine bar_wrapper
    

    或最终,在间接和包装中用延迟大小替换所有假定大小,以便给运行时检查提供机会,也有效,但这不是重点......

    关键是,因为我有很多这样的foo / bar,没有办法正确地声明接口(我的意思是没有包装器或其他人工制品)。

    我无法破译标准(我使用http://www.j3-fortran.org/doc/year/10/10-007.pdf - 我认为它在 12.5.2.9与虚拟过程实体相关的实际参数§2),所以我不知道如果这是gfortran的限制。现在我没有任何其他编译器可用,但我想知道是否有其他编译器可以编译(英特尔? - 我在Windows 7 64位)。

1 个答案:

答案 0 :(得分:3)

我会看看gfortran是否正确抱怨,无论如何,有什么选择可以解决投诉。参考资料是Fortran 2008。

12.5.2.9确实很重要。

  
      
  1. 如果伪过程的接口是显式的,那么作为过程(12.3.1)的特征应与其有效参数的特征相同,除了[不适用的东西]
  2.   
f中的

indirect是一个带有显式接口的虚拟过程(通过接口块; 12.4.2.1)。看一下参考文献12.3.1,我们看到了

  

程序的特征是..,其伪参数的特征,..

foobarf都是具有单个伪参数的过程(全部称为p,巧合)。因此,如果foo希望成为与f相关联的有效参数,那么foo的{​​{1}}必须符合p的{​​{1}}的特征}。每个f都是一个虚拟数据对象,因此12.3.2.2变得相关:

  

虚拟数据对象的特征是它的类型,类型参数(如果有的话),它的形状,......如果假定或推迟了形状,大小或类型参数,那么它就是一个特征。

我们有类型和类型参数匹配。但是,p中的p会假设其大小。 p中的f没有此匹配特征。因此,不允许在p的调用中将foofoo相关联。同样适用于f

将虚拟数据对象的特征匹配为具有相同形状的这一要求自然会导致另一个结论:indirectbar没有匹配的特征作为过程。要使第三个程序匹配,必须忽略形状特征。

使用包装器子程序是可能的,但我还要考虑是否可以更改各种子程序以采用假定形状参数。这比假设大小要好得多。但是,正如你所说,我也不愿意改变这些代码。

对于子例程foobar,您可以使用另一个选项。这些子例程没有任何内容要求调用者为它们提供明确的接口(12.4.2.2)。因此,在foo中你可以废弃接口块:关于匹配的规则要宽松得多(12.5.2.9的其他部分)。但是,对于其他程序,这可能是不可能的。

所有这一切,ifort似乎很乐意编译并运行你的代码......