【问题标题】:Can the shape of an array in an interface match multiple fixed array size?接口中数组的形状可以匹配多个固定数组大小吗?
【发布时间】:2015-06-03 12:49:19
【问题描述】:

我有多个带有参数 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 不是我的代码,我不想更改它们...

我找到了一种解决方法,但它包括为每个子例程 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 位上)。

【问题讨论】:

  • 注意:(*) 是假定的大小,而不是假定的形状。区别其实很重要。假定形状为(:)
  • @VladimirF 谢谢,已更正,我被编译器错误消息滥用了

标签: fortran fortran95


【解决方案1】:

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

12.5.2.9 确实很重要。

  1. 如果虚拟过程的接口是显式的,则其作为过程 (12.3.1) 的特性应与其有效参数的特性相同,除了 [不适用的事物]

indirect 中的f 是具有显式接口的虚拟过程(通过接口块;12.4.2.1)。查看参考12.3.1我们看到

过程的特征是..,它的虚拟参数的特征,..

foobarf 都是具有单个虚拟参数的过程(巧合的是,它们都称为 p)。因此,如果foo 想要成为与f 关联的有效参数,那么foop 必须匹配fp 的特征。每个p 都是一个虚拟数据对象,因此 12.3.2.2 变得相关:

虚拟数据对象的特征是它的类型、它的类型参数(如果有的话)、它的形状……如果假设或延迟了形状、大小或类型参数,它就是一个特征。

我们有类型和类型参数匹配。但是,f 中的 p 假定其大小。 foo 中的 p 没有这个匹配特征。因此,在对indirect 的调用中,不允许将foof 关联。 bar 也是如此。

这个要求虚拟数据对象的特征匹配具有相同的形状自然也导致另一个结论:foobar不具有作为过程的匹配特征。对于匹配这两个形状特征的第三个过程,必须忽略。

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

对于子例程foobar,您拥有它们,还有另一个可用选项。这些子例程不需要调用者为它们提供显式接口(12.4.2.2)。因此,在indirect 中,您可以废弃接口块:关于匹配的规则要宽松得多(12.5.2.9 的其他部分)。但是,对于其他程序,这可能是不可能的。

话虽如此,ifort 似乎很高兴地编译和运行您拥有的代码...

【讨论】:

  • 谢谢,这必须符合 gfortran 的解释。但是,如果我将 foo 和 bar 的签名降级为假定维度(),它们就会匹配接口并且编译器保持安静......这纯粹是人为的,因为仍然会使用 p 中的 2 和其他 3 个元素......而且我猜在这两种情况下,实现都只使用指向第一个数组元素的原始指针,假设维度 () 或显式 (2),所以它们是二进制兼容的......我觉得说显式接口假设的数组大小有点毛茸茸;)
  • 假定的形状/大小确实与显式不同。如果您觉得明确的形状很重要(而且可能很重要),那么我可以想到两件事:想通过indirect 将它们混为一谈是没有意义的;有indirectf 有一个隐式接口(废弃接口块)。这最后一个我可能实际上应该放在答案中......
  • 是的,间接在我的示例中没有任何意义,但它可以是 ODE 求解器、SLLSQP 求解器或其他任何东西......如果我将求解器用于不同的问题,我将有不同的大小。
猜你喜欢
  • 2015-10-24
  • 2023-04-03
  • 2012-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-17
  • 2022-01-23
  • 1970-01-01
相关资源
最近更新 更多