假设有一个向量:
REAL(KIND=dp), DIMENSION(maxn) :: rho
在初始子程序中分配值(连同 dp
和 maxn
)并从主程序中调用。
然后主程序调用一个包含(不同的)子例程的模块来进化rho
。 rho
的子例程参数定义为:
SUBROUTINE sum_density(a, b, c, ....., rho)
在此子例程中,rho 声明为:
REAL(KIND=dp), DIMENSION(maxn), INTENT(OUT) :: rho
然而,在与 rho
关联的任何值之前,代码包含以下行:
foo1= foo2*foo3(i)/rho(i)
我原以为模块子例程不会访问主程序中定义的rho
。我希望编译器会提示并要求将意图更改为 (INOUT)
或说 rho
之类的内容未定义。即使我将其更改为 (INOUT)
,结果也没有区别。模块子例程必须在主程序中访问 rho
的值并使用它,即使意图被声明为 OUT
。
我的问题是 - 在这种情况下,使用 INTENT(OUT)
和 INTENT(INOUT)
有什么区别?
最佳答案
使用 INTENT(OUT)
程序不符合标准,因为它访问具有未定义值的数组。
但是,软件实现可能会起作用,因为显式形状数组通常是通过传递数组地址来实现的。如果您传递的数组是不连续的,假设
rho(::2)
编译器很可能会创建一个副本,该副本被通过并且您可能会遇到问题,因为数组可能包含 intent(out)
的垃圾。
关于警告,它们不是强制性的,但如果您使用 -warn
或 -Wall
等标志,编译器会对此发出警告。
对于 intent(in)
,当您尝试修改 rho
时,差异就会出现。如果您尝试编译器必须发出错误。
关于范围:
这里说作用域是不正确的,原来的rho
肯定不在子程序的作用域内,只有dummy argument在。重复使用相同的名称可能会造成混淆。想象一下,它们实际上在程序中称为 rho1
,在子例程中称为 rho2
。那么很明显rho1
不在子程序的范围内,但是rho2
在。
现在,rho2
不能保证在带有 intent(out)
的子例程开始时具有与 rho1
相同的值,但是它保证有 intent(inout)
。原因是参数传递可以使用复制输入和复制输出来实现,并且对于 intent(out)
可以省略复制。
考虑这段代码:
module m
contains
subroutine sub(a2)
real, intent(out) :: a2(4)
print *,a2
a2 = 2
end subroutine
end
use m
real :: a1(8)
a1 = 1
call sub(a1(::2))
end
对于某些编译器,它会打印 4 次,正如人们所期望的那样,但对于其他编译器或某些编译器参数,它会打印垃圾:
sunf90 intent2.f90
./a.out
5.879759E-39 0.0E+0 0.0E+0 0.0E+0
关于module - Fortran - 模块子例程参数意图混淆 - INOUT 与 OUT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25847014/