Fortran 是否复制传递给函数/子例程的数组部分?

a c*_*zen 3 c++ arrays fortran

当将数组部分传递给 Fortran 中的子例程时,例如f(a, b, c(2:5,4:6))(所有这些都是二维数组),程序是先制作 的临时副本c,然后将其传递给子例程(作为引用、指针等),还是整个过程动态处理?

我正在尝试将一些 Fortran 代码转换为 C++,并且我看到对具有作为参数传递的数组部分的子例程的调用。据我所知,C++ 不允许这样做,所以我试图在 C++ 中像这样(mat2d = std::vector<std::vector<T>>):

f(mat2d &a, mat2d &b, mat2d *a, int rows, int rows, int offsetx, int offsety) {...}
Run Code Online (Sandbox Code Playgroud)

并调用为:

f(a, b, c.data(), ...)
Run Code Online (Sandbox Code Playgroud)

这有效,但它需要大小,以及我想要进行通用矩阵乘法的情况下的偏移量(例如)。所以,如果 Fortran 首先复制c(2:5,4:6)到(比如说)一个temp(4,3)数组,那么我可以在 C++ 中模仿它:简单地复制一个临时的,然后将该临时的引用传递给函数,没有行/列/偏移量. 但如果不是……我不介意听听别人的想法。


示例子程序:

subroutine f(A, B, C)
  implicit none
  real(kind(1d0)) :: A(2,2), B(2,2), C(2,2)
  C = A*B
  return
end f
Run Code Online (Sandbox Code Playgroud)

如果我的话不好,也许一张带有真实代码的图片就可以了?阵列是auxfour(4,4)aux44(4,4),和Gv(2,2)

代码

这是一个调用,具有auxp(5)相同的Gv

代码2

完整的子程序。图片,不是文字。

子

Vla*_*r F 6

诚然,Fortran 标准并没有规定传递机制的细节。然而,因为编译器正在努力提高效率,我们可以说很多关于实践中通常会发生的事情。

Fortran 标准没有指定通过引用传递参数,但规则实际上要求它。但是,它始终可以是对临时副本的引用。引用通常仅表示第一个元素的内存地址(指针)。当一个人只传递一个元素并在子例程/函数内引用整个数组时,这使得完全有效的用法成为可能。

在某些情况下,临时副本实际上是不可避免的。

让我们考虑一下

real :: a(10,10)

call f(a(2:5,4:6))
Run Code Online (Sandbox Code Playgroud)

那么如果f

subroutine f(c)
  real :: c(3,3)
Run Code Online (Sandbox Code Playgroud)

那么编译器可以做的很少,临时副本实际上是有保证的。同样适用于

subroutine f(c)
  real :: c(3,*)
Run Code Online (Sandbox Code Playgroud)

然而,对于假定的形状数组

subroutine f(c)
  real :: c(:,:)
Run Code Online (Sandbox Code Playgroud)

事实并非如此。这些参数是使用数组描述符传递的,并且可以是不连续的,您通常不会看到它们的临时副本。

最后,如果第一个维度是完整的:

real :: a(2:5,10)

call f(a(:,4:6))
Run Code Online (Sandbox Code Playgroud)

副本也不是必需的,因为子数组在内存中是连续的。


即使不需要临时文件,编译器也总能做到,但没有任何保证。但在实践中不太可能。编译器力求高效。