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:
完整的子程序。图片,不是文字。
诚然,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)
副本也不是必需的,因为子数组在内存中是连续的。
即使不需要临时文件,编译器也总能做到,但没有任何保证。但在实践中不太可能。编译器力求高效。