我正在阅读Fortran代码,有一点让我感到有些困惑。
有一个子程序,比如说
SUBROUTINE SSUB(X,...)
REAL*8 X(0:N1,1:N2,0:N3-1),...
...
RETURN
END
在另一个子程序中通过以下方式调用:
CALL SSUB(W(0,1,0,1),...)
其中W是'工作数组'。看来W中的特定值传递给X,但X的大小为数组。发生了什么事?
答案 0 :(得分:7)
这是让子程序在原始数组的(N维矩形)子集上工作的非常常见的习惯用法。
Fortran中的所有参数(至少在Fortran 90之前)都是通过引用传递的,因此实际的数组参数将被解析为内存中的一个位置。在里面选择一个位置为整个数组分配的空间,子程序只操作数组的一部分。
最大问题:您必须be aware of how the array is laid out in memory以及Fortran的数组索引方案如何运作。 Fortran使用列主要数组排序,这与c相反。考虑一个大小为5x5的数组(并且从0开始指向两个方向,以便与c进行比较更容易)。在两种语言中,0,0是内存中的第一个元素。在c中,内存中的下一个元素是[0][1]
,但在Fortran中它是(1,0)
。这会影响您在选择子空间时删除哪些索引:如果原始数组是A(i,j,k,l),并且子例程在三维子空间上工作(如在您的示例中),则在c中它适用于{{ 1}},但在Fortran中的Aprime[i=constant][j][k][l]
上工作。
另一个风险是环绕。子例程中(子)数组的维度必须与调用例程中的维度匹配,否则会发生奇怪的奇怪事情(想一想)。因此,如果A被声明为size(0:4,0:5,0:6,0:7),并且我们使用元素Aprime(i,j,k,l=constant)
调用,则接收例程可以自由地启动每个维度的索引它喜欢,但必须使尺寸A(0,1,0,1)
或其他;但这意味着j方向的最后一个元素实际上是环绕的!要做的是不使用最后一个元素。确保发生这种情况是程序员的工作,并且是一个痛苦的屁股。照顾自己。很多照顾。
答案 1 :(得分:2)
是通过地址传递的。
所以W(0,1,0,1)
是价值和地址。所以基本上你从W(0,1,0,1)
开始传递子阵列。
答案 2 :(得分:2)
这称为“序列关联”。在这种情况下,似乎是缩放器,数组的元素(调用者中的实际参数)与数组(隐式第一个元素),子例程中的伪参数相关联。此后,阵列的元素通过存储顺序关联,称为“序列”。这是在Fortran 77及更早版本中出于各种原因完成的,这显然是针对工作区数组 - 也许程序员正在进行自己的内存管理。为了向后兼容性,这在Fortran> = 90中保留,但IMO不属于新代码。