FORTRAN 77 中子例程参数的范围
Scope of subroutine parameters in FORTRAN 77
我有一个声明 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
的值,但是它们不应替换 smallSub1
中 i
的原始值
来自 https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html
Fortran 通过引用传递大多数参数
因此,如果不想让变量改变,就不要在子程序中改变它。您可以将变量 smallSub1(i) 重命名为 smallSub1(j)
你不想改变整个功能。
在给定的代码示例中有两个变量i
:每个子例程一个。在子程序 caller
中,i
是一个局部变量,而在子程序 smallSub1
中,它是一个伪参数。
当你有 call smallSub1(i)
时,你通过参数关联将两个 i
变量相互关联。那么,在这个简单的例子中,smallSub1
中 i
的任何更改都会影响 caller
中的 i
。这里有参数关联的工作原理。
传统上确实有黑匣子,当不需要时,子例程中的参数会被更改。用作作品的地方——例如space。在那种情况下,人们会做类似
的事情
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 通常通过引用传递,当不可能时,它会执行类似 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
不会更改 [=17= 中的 i
]
为了帮助避免这种行为,您可以向编译器提示伪参数用于输入、输出或两者。如果您在原始示例中的 smallSub1
中将 i
声明为 integer, intent(in) :: i
,则编译器会抱怨:
do i=start, end
1
Error: Dummy argument ‘i’ with INTENT(IN) in variable definition context (iterator variable) at (1)
让您意识到您正在对虚拟参数进行不需要的更改。
我有一个声明 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
的值,但是它们不应替换 smallSub1
i
的原始值
来自 https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html Fortran 通过引用传递大多数参数
因此,如果不想让变量改变,就不要在子程序中改变它。您可以将变量 smallSub1(i) 重命名为 smallSub1(j) 你不想改变整个功能。
在给定的代码示例中有两个变量i
:每个子例程一个。在子程序 caller
中,i
是一个局部变量,而在子程序 smallSub1
中,它是一个伪参数。
当你有 call smallSub1(i)
时,你通过参数关联将两个 i
变量相互关联。那么,在这个简单的例子中,smallSub1
中 i
的任何更改都会影响 caller
中的 i
。这里有参数关联的工作原理。
传统上确实有黑匣子,当不需要时,子例程中的参数会被更改。用作作品的地方——例如space。在那种情况下,人们会做类似
的事情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 通常通过引用传递,当不可能时,它会执行类似 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
不会更改 [=17= 中的 i
]
为了帮助避免这种行为,您可以向编译器提示伪参数用于输入、输出或两者。如果您在原始示例中的 smallSub1
中将 i
声明为 integer, intent(in) :: i
,则编译器会抱怨:
do i=start, end
1
Error: Dummy argument ‘i’ with INTENT(IN) in variable definition context (iterator variable) at (1)
让您意识到您正在对虚拟参数进行不需要的更改。