FORTRAN 77中子程序参数的范围

时间:2015-05-22 15:19:53

标签: fortran fortran77

我有一个子例程声明i并将其传递给其他小子例程。在那些小的子程序中,声明了具有相同名称的其他变量,即i,并且它在内部使用。一旦超出小子例程,就会期望具有与最初传递的值相同的i,但这不是真实情况,i包含在小子例程中分配的最后一个参数的值。这是一个简短的例子:

subroutine smallSub1(i)
 integer i,start,end
 start=i
 end = start +10
 do i=start, end
    write(*,*) i
 enddo
end subroutine smallSub1

subroutine caller
integer i
i = 1
call smallSub1(i)
write(*,*) i
end subroutine caller

我的问题是,我怎样才能在F77中避免这种行为?

我关注的是:考虑一个子程序是黑盒子的情况,你只需要传递一个整数,但是你不希望那个整数值从smallSub1子程序改变。变量startend取决于i的值,但它们不应取代ismallSub1的原始值

3 个答案:

答案 0 :(得分:2)

正如在另一个答案中所指出的,Fortran通常通过引用传递,当不可能时,它会执行诸如copy-in / copy-out之类的操作。正如其他人在评论中简洁地说的那样,如果您不想更改i,请不要更改i

在子例程smallSub1中,i被用作循环迭代变量,并且您不希望其值更改对调用者可见。更改icaller可见的原因是因为i不是局部变量,而是伪参数。解决方案是通过不同的名称调用循环变量和伪参数。一个这样的解决方案是:

subroutine smallSub1(i_from_caller)
  integer  i,i_from_caller,start,end
  start = i_from_caller
  end = start +10
  do i=start, end
     write (*,*) i
  end do
end subroutine smallSub1

在这种情况下,伪参数已重命名为i_from_caller,用于初始化start。现在,循环变量i对于子例程来说是真正本地的(因为它不再是伪参数的名称),并且此处更改i不会更改i caller }

为了帮助避免这种行为,您可以给编译器提示伪参数用于输入,输出或两者。如果您在原始示例中的i中声明integer, intent(in) :: ismallSub1,则编译器会抱怨:

     do i=start, end
       1
Error: Dummy argument ‘i’ with INTENT(IN) in variable definition context (iterator variable) at (1)

让您意识到您正在对虚拟参数进行不必要的更改。

答案 1 :(得分:1)

来自https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html

Fortran通过引用传递大多数参数

因此,如果您不希望变量发生变化,请不要在子程序中更改变量。您可以将变量smallSub1(i)重命名为smallSub1(j) 你不想改变整个功能。

答案 2 :(得分:1)

在给出的代码示例中,有两个变量i:每个子例程中有一个变量。在子例程caller中,i是局部变量,在子例程smallSub1中,它是一个伪参数。

当你有call smallSub1(i)时,你通过参数关联将两个i变量相互关联。在这个简单的情况下,i中对smallSub1的任何更改都会影响i中的caller。论证关联在这里有效。

传统上有一个黑盒子,当不需要时,子程序中的参数会发生变化。例如,它被用作工作空间的地方。在这种情况下,人们会做类似

的事情
inew = i
call smallSub1(inew)
... continue using i

然而,在这种情况下,人们可以很容易地(我想象)改变子程序。引入一个额外的局部变量:

subroutine smallSub1(i)
  integer i   ! Dummy argument - we don't want to change it
  integer start,end
  integer j   ! Local variable - we're quite free to change it
              ! In general, we'd have j=i at the start and use that instead
  start=i
  end = start +10
  do j=start, end
     write(*,*) j
  enddo
end subroutine smallSub1

使用现代Fortran,即使具有value属性,也可以应用于伪参数,允许人们更改它而不会影响实际参数。