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

C++ Fortran是否复制传递给函数/子例程的数组部分?,c++,arrays,fortran,C++,Arrays,Fortran,当用Fortran将数组的部分传递给子程序时,例如f(a,b,c(2:5,4:6))(所有这些数组都是2D数组),程序是先临时复制c,然后将其传递给子程序(作为引用、指针等),还是整个过程都是动态处理的 我试图将一些FORTRAN代码转换成C++,我看到调用子程序,这些子程序将数组的部分作为参数传递。据我所知,C++不允许这样,所以我试图在C++中绕过这个(如:代码> Mat22= STD::向量< /代码>): 并致电: f(a, b, c.data(), ...) 这是可行的,但它需要大小

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

我试图将一些FORTRAN代码转换成C++,我看到调用子程序,这些子程序将数组的部分作为参数传递。据我所知,C++不允许这样,所以我试图在C++中绕过这个(如:代码> Mat22= STD::向量< /代码>):

并致电:

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))
由于子阵列在内存中是连续的,因此也不需要复制



即使在不需要临时文件的情况下,编译器也可以随时创建临时文件,但不保证任何内容。但在实践中不太可能。编译器试图提高效率。

这实际上取决于Fortran子例程(您没有显示)。Fortran还可以传递非连续数组的数组描述符。@VladimirF我添加了一些伪造的,类似于我在Fortran代码中看到的示例。如果不是,请考虑Buffin ,这也是我感兴趣的。我还有类似于
x(1:2,:)=matmul(y,z(1:2,:)
。但我对传递数组片段的任何情况都感兴趣:这是副本吗?您使用的编译器是什么?gfortran有一个选项可以告诉您何时创建临时数组。上床睡觉吧,但简短的回答是,您最初的问题没有答案,因为Fortran标准没有说明是否需要复制—它只说明结果应该是什么。这在Fortran中很常见,只要结果正确,编译器可以随意实现它。因此,一个编译器可以复制,另一个编译器可能不会。同一编译器的不同版本可能会执行不同的操作。您只能依赖于结果是什么,而不能依赖于如何实现该结果。@ja72我不使用英特尔编译器,但我认为它类似于上面评论中提到的g++。但是,是的,这是非常有用的,并且(部分)导致了结论。
real :: a(2:5,10)

call f(a(:,4:6))