例如,将数组的各节传递给Fortran中的子例程时, f(a, b, c(2:5,4:6))
(所有都是2D数组),程序是先制作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) {...}
并呼叫为:
f(a, b, c.data(), ...)
这是可行的,但是它需要大小,并且在我要进行通用矩阵乘法的情况下也需要偏移(例如)。因此,如果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
如果我的单词不好,也许一张带有真实代码的图片会起作用吗?数组为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))
然后,如果f
为
subroutine f(c)
real :: c(3,3)
然后编译器几乎无能为力,实际上可以保证临时副本。同样适用于
subroutine f(c)
real :: c(3,*)
但是,对于假定的形状数组
subroutine f(c)
real :: c(:,:)
并非如此。这些参数是使用数组描述符传递的,并且可以是非连续的,通常不会看到它们的临时副本。
最后,如果第一维完成:
real :: a(2:5,10)
call f(a(:,4:6))
也不需要复制,因为子数组在内存中是连续的。
即使不需要临时文件,编译器也总能做到,没有任何保证。但这在实践中不太可能。编译器尝试提高效率。