FORTRAN 77中子程序参数的范围

FORTRAN 77中子程序参数的范围,fortran,fortran77,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 en

我有一个子例程,它声明
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
子例程更改。变量
start
end
将取决于
i
的值,但是它们不应替换
i
的原始值,而不是从
smallSub1
中删除 Fortran通过引用传递大多数参数

因此,如果不想更改变量,请不要在子例程中更改它。您可以将变量smallSub1(i)重命名为smallSub1(j) 您不想更改整个函数。

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

因此,如果不想更改变量,请不要在子例程中更改它。您可以将变量smallSub1(i)重命名为smallSub1(j)
您不想更改整个函数。

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

当您有
调用smallSub1(i)
时,您通过参数关联将两个
i
变量彼此关联起来。在这种简单的情况下,
smallSub1
中对
i
的任何更改都会影响
调用者中的
i
。这里有参数关联的工作原理

传统上,人们确实有一个黑匣子,在这个黑匣子中,一个参数在不需要的时候在子例程中被改变。例如,将其用作工作空间的位置。在这种情况下,一个人会做这样的事情

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
属性,该属性可以应用于伪参数,允许用户在不影响实际参数的情况下更改它。

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

当您有
调用smallSub1(i)
时,您通过参数关联将两个
i
变量彼此关联起来。在这种简单的情况下,
smallSub1
中对
i
的任何更改都会影响
调用者中的
i
。这里有参数关联的工作原理

传统上,人们确实有一个黑匣子,在这个黑匣子中,一个参数在不需要的时候在子例程中被改变。例如,将其用作工作空间的位置。在这种情况下,一个人会做这样的事情

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
属性,它可以应用于伪参数,允许用户在不影响实际参数的情况下对其进行更改。

如另一个答案中所述,Fortran通常通过引用进行传递,当这不可能时,它会执行诸如“复制入/复制出”之类的操作。正如其他人在评论中简洁地说的那样,如果你不想更改
i
,那么就不要更改
i

在子例程
smallSub1
中,
i
被用作循环迭代变量,并且您不希望其值更改对调用方可见。更改
i
的原因对调用方可见,因为
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\u,用于初始化
start
。现在循环变量
i
确实是子例程的本地变量(因为它不再是伪参数的名称),在这里更改
i
不会在
调用者中更改
i


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

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

使您意识到您正在对伪参数进行不必要的更改。

如另一个答案中所述,Fortran通常通过引用进行传递,当这不可能时,它会执行诸如复制入/复制出之类的操作。正如其他人在评论中简洁地说的那样,如果你不想更改
i
,那么就不要更改
i

在子例程
smallSub1
中,
i
被用作循环迭代变量,并且您不希望其值更改对调用方可见。更改
i
的原因对调用方可见,因为
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\u,用于初始化
start
。现在,循环变量
i
确实是子循环的局部变量