考虑:
program main
real, allocatable, dimension(:) :: foo
integer n
n=10
call dofoo(foo,n,1)
allocate(foo(n))
call dofoo(foo,n,0)
end program main
subroutine dofoo(foo,n,mode)
real foo(n)
integer i,n,mode
if(mode.eq.1)then
n=6
return
endif
do i=1,n
foo(i)=i
enddo
return
end subroutine dofoo
上述代码有什么问题吗? (它适用于gfortran)我第一次传入一个未分配的数组,但是我没有触及它 - 标准中是否有任何可能导致它以系统相关方式运行的内容?
答案 0 :(得分:5)
你几乎回答了自己的问题。是的,根据标准,如果您在范围内没有接口,则将未分配的可分配数组作为实际参数传递始终是非法的。
如果你在范围内有一个接口,那么伪参数也是可分配的,这是合法的。
是的,我被它咬了。我的工作是在通话前分配到零大小。
答案 1 :(得分:3)
answer by Ian Bush 正确说明问题中不允许使用。不过,我们可以更精确。 (括号中是 Fortran 2018 标准的参考。)
可以使用未分配的可分配实参的三种情况:
“未使用”的虚拟参数也不例外。无论可分配参数是数组还是标量,这些限制都适用。
任何其他用途都意味着该程序不符合标准 (15.5.2.4 p.7, 15.5.2.7 p.2)。
在符合标准的程序中,这些可接受的情况中的每一个都有一个可用的显式接口。可分配或可选的虚拟参数需要一个 (15.4.2.2 p.1(3)),并且可访问的内部过程始终具有可用的显式接口 (15.4.2.1 p.1)。
对程序的这些要求不是编译器required to be able to analyse。这种不符合标准的程序并不一定意味着您在编译和运行时会看到问题。在问题的程序的情况下,它不会试图以一种糟糕的方式取消引用,你很可能会逃脱它。然而,编写不符合规范的程序并不好,依赖它们“工作”是非常糟糕的。
有一些事情可能会出错:
value
属性的虚拟对象(同样,在这种情况下需要显式接口)也就是说,您的程序可能会因某些编译器/编译器选项而表现不同。如果你的编译器注意到你应该有一个可用的显式接口,它可能会拒绝编译程序。如果运行时检查参数是否已分配,则程序可能会在进入子例程时中止。如果在未分配实际参数时尝试使用 value
属性创建数组的匿名可定义副本,运行时可能会做一些非常意外的事情。
对于这个问题,还有另一个不合规问题需要担心。显式长度虚拟参数 foo(n)
表示实际参数必须至少包含 n
元素。未分配的数组至少没有 n
元素(对于任何,甚至零,n
)。如果 foo
是 intent(out)
,编译器将在其权限范围内做一些事情来“取消定义”实际参数的这些元素。这可能会失败。