我有一个子例程声明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
的原始值
答案 0 :(得分:2)
正如在另一个答案中所指出的,Fortran通常通过引用传递,当不可能时,它会执行诸如copy-in / copy-out之类的操作。正如其他人在评论中简洁地说的那样,如果您不想更改i
,请不要更改i
。
在子例程smallSub1
中,i
被用作循环迭代变量,并且您不希望其值更改对调用者可见。更改i
对caller
可见的原因是因为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) :: i
为smallSub1
,则编译器会抱怨:
do i=start, end
1
Error: Dummy argument ‘i’ with INTENT(IN) in variable definition context (iterator variable) at (1)
让您意识到您正在对虚拟参数进行不必要的更改。
答案 1 :(得分:1)
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
属性,也可以应用于伪参数,允许人们更改它而不会影响实际参数。