Fortran - 模块子例程参数意图混淆- INOUT vs OUT

3
假设有一个向量:
REAL(KIND=dp), DIMENSION(maxn) ::  rho

这个变量是在一个初始子程序中分配的(与dpmaxn一起),然后从主程序中调用。

然后,主程序调用一个包含(不同的)子程序以演化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) 有什么区别?


2
你在上一句话中真的是想要使用 INTENT(IN) 吗? - Vladimir F Героям слава
哎呀,谢谢你指出了这个问题 - 已修复。 - 1QuickQuestion
1个回答

4
使用INTENT(OUT),程序不符合标准,因为它访问具有未定义值的数组。
然而,由于显式形状数组通常是通过传递数组地址来实现的方式,软件实现很可能会正常工作。如果你传递的数组是非连续的,例如:
  rho(::2)

编译器可能会创建一个副本进行传递,如果数组包含 intent(out) 的垃圾数据,则可能遇到问题。关于警告,它们并不是必需的,但如果使用诸如 -warn-Wall 等标志,编译器会发出警告。
对于 intent(in),当您尝试修改 rho 时,差异就会显现出来。如果您这样做,编译器将必须发出错误。
关于作用域:
在这里谈论作用域并不完全正确,原始的 rho 肯定不在子程序的作用域内,只有虚拟参数在作用域内。重复使用相同的名称可能会令人困惑。想象一下,它们实际上在程序中被称为 rho1,在子程序中被称为 rho2。然后可以清楚地看出,rho1 不在子程序的作用域内,但是 rho2 在其中。
现在,在 intent(out) 的情况下,不能保证 rho2 具有与子程序开始时相同的值,但是在 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

在某些编译器中,它会打印出四个“one”,这是我们所期望的。然而,在其他编译器或使用某些编译器参数时,它会打印出垃圾信息。

sunf90 intent2.f90 
./a.out 
 5.879759E-39 0.0E+0 0.0E+0 0.0E+0

谢谢您的回答(并指出我在问题的最后一句中的拼写错误)。那么,您能否澄清一下,如果将INTENT声明为OUT,最初声明的rho是否通常超出模块的范围?您是说它由于显式形状数组的实现方式而被引入范围内吗? - 1QuickQuestion
1
在模块过程中,最初声明的 rho 变量无论 intent 如何它都不在作用域内。然而,与之相关联的内存也与模块过程中的虚拟参数相关联。 - bdforbes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接