7

考虑:

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)我第一次传入一个未分配的数组,但我没有触及它——标准中是否有任何东西可能导致它以系统依赖的方式运行?

4

2 回答 2

6

你几乎已经回答了你自己的问题。是的,按照标准,如果您在范围内没有接口,则将未分配的可分配数组作为实际参数传递总是非法的。

如果您在范围内有一个接口,则只有当虚拟参数也是可分配的时才合法。

是的,我被它咬了。我的工作是在调​​用之前分配为零大小。

于 2012-11-21T15:44:44.153 回答
3

伊恩布什的回答正确地指出问题中的使用是不允许的。不过,我们可以更精确。(括号中引用了 Fortran 2018 标准。)

在三种情况下,可以使用未分配的可分配实际参数:

  • 当虚拟参数也是可分配的(仅自 Fortran 2003 或 Fortran 95+TR-15581 起)(15.5.2.6 p.2)
  • 当虚拟参数是可选的普通参数时(仅自 Fortran 2008 起)(15.5.2.12 p.1、15.5.2.4 p.7)
  • 当过程是内在查询功能时(15.5.2.4 p.7、16.1 p.2)

“未使用”的虚拟参数也不例外。无论可分配参数是数组还是标量,这些限制都适用。

任何其他用途意味着程序不符合标准(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)。

这些对程序的要求并不是编译器必须能够分析的。这样一个不符合标准的程序并不一定意味着你在编译和运行的时候会看到问题。在问题程序的情况下,它不会试图以不好的方式取消引用,你很可能会侥幸逃脱。但是,编写不符合标准的程序并不好,依赖它们“工作”非常糟糕。

有一些事情可能会出错:

  • 运行时检查
  • 编译时检查
  • value具有属性的假人(同样,在这种情况下需要显式接口)

也就是说,您的程序在某些编译器/编译器选项下的行为可能会有所不同。如果你的编译器注意到你应该有一个可用的显式接口,它可能会拒绝编译程序。如果运行时检查参数是否已分配,程序可能会在进入子例程时中止。value如果在未分配实际参数的情况下尝试使用属性创建数组的匿名可定义副本,运行时可能会做一些非常意外的事情。


对于这个问题,还有另一个不合规需要担心。显式长度伪参数foo(n)意味着实际参数必须至少有n元素。未分配的数组至少没有n元素(对于任何元素,甚至为零n)。如果foointent(out)编译器将在其权利范围内做一些事情来“取消定义”实际参数的这些元素。这可能会失败。

于 2021-06-21T14:49:54.150 回答