Fortran:如何为可选数组虚拟Arg强制“未定义地址”?

时间:2014-10-09 16:19:12

标签: pointers fortran undefined

Fortran:如何为可选数组虚拟Arg强制“未定义地址”?

我有一个情况(长篇故事,请不要问“为什么”)需要在Call语句中“留下”一个实际的可选Arg到一个带有可选数组虚拟Args的s / r,但仍然有它们被视为.NOT。出现在某些情况下。例如

Integer, Target :: n
Integer, Pointer    :: m
!
Real(DP), Target    :: ArrA(n)
Real(DP), Pointer   :: ArrB(:)
!
Logical     :: lSomething
!
m => n
!
If( lSomething ) Then
   n = 5
Else
   Nullify(m)
End If
!
Allocate(ArrB(n))
!
ArrB => ArrA
!
If( lSomething ) Then
   ArrA(1:n) = (/"... n values ..."/)
Else
   Nullify(ArrB)
End If
!
Call sr(ArrA, ArrB,n, m)    ! the idea is for ArrB, and m to "pretend" to be .Not. Present if they are Null.
!

....

Subroutine sr(A,BX,n, mX)   ! where the suffix "X" is my notation for Optional Vars
!
Integer, Intent(In)         :: n
Real(DP), Intent(In)        :: A(n)
!
Integer, Intent(In), Optional   :: mX
Real(DP, Intent(In), Optional   :: BX(:)
!
If( Present(mX) ) Then      ! this works correctly with Nullify'd pointer, when mX = "undefined pointer/array"
   !
   ! do something
End If
!
If( Present(BX) ) Then      ! this works INcorrectly with Nullify'd pointer, when BX = "undefined pointer/array", but works correctly if BX has the value "undefined address"
   !
   ! do something else
End If
.....

目前,我使用的策略是在调用序列中创建一个指向Optional的指针并传递指针。

要清楚,当实际的Args(指针)指向“正确的值”或数组时,这一切都有效。当试图通过在其位置发送Null Pointer来“假装”已经省略了可选Arg时,问题出现了。

如果Pointer为Nullify'd,则s / r接收一个值为“undefined pointer / array”的Arg(应该如此)。

虚拟Args不是指针,它们是普通的vars。

然后,这个想法是“未定义的”虚拟Arg显示为“不存在”。例如,在行If(Present())中,未定义的var应注册为“.Not.Present”。

此策略适用于标量Args。那就是:

If( Present(mX) ) Then
   ! do something
End If

然后,如果m作为Nullify'd指针传递,则mX具有“value”“undefined pointer / array”,并且If(Present(mX))语句在“mX is .NOT。present”中正确运行“(即未达到”做某事“)。

不幸的是,这对于Optional数组来说是失败的。例如,在上面完全相同的策略(虽然必须将指针分配为与BX()一致的秩,并且Nullify'ing),var BX具有值“未定义指针/数组”...但是存在(BX)查询报告.TRUE ..即,即使虚拟数组var是“未定义指针/数组”,它仍然是“存在”。然后,即使它是NUll,也会达到“做其他事情”......当它不应该出现时。

我的猜测是,分配实际Arg的行为,即使它是Nullify'd,在内存中创建一个“无数组”,就Present()而言仍然是“某事”(尽管如此,例如,尺寸(BX)是< 1)。

相反,如果实际省略了Optional Arg ArrB,例如:

Call sr(ArrA, n = n, mX = m)

然后它的虚拟Arg,BX,具有“值”“未定义的地址”。与通过Nullify的“未定义指针/数组”相比,这是不同的。

换句话说,显然,要使Present()查询与数组Args一起正常工作,“值”必须是“未定义的地址”,而不是“未定义的指针/数组”。

有谁知道如何强制数组(虚拟)Arg具有值“未定义地址”(而不是“未定义指针/数组”)?或者让Present()查询与标量和数组保持一致?或???

2 个答案:

答案 0 :(得分:0)

你的问题很难理解。我猜你的意思是这样的。您绝对不必分配指针或可分配数组以在可选参数中传递它。

program p
  integer, pointer :: a(:) => null()

  call sub()

  call sub(a)

  allocate(a(10))
  a = 0

  call sub(a)

  deallocate(a)

contains
  subroutine sub (ptr)
    integer, pointer, optional :: ptr(:)
    if (present(ptr)) then
      if (associated(ptr)) then
        print *, "present associated"
      else
        print *,"not associated"
      end if
    else
      print *, "not present"
    end if
  end subroutine
end

您可以查询参数是否存在以及是否相关。

输出:

> ./a.out
 not present
 not associated
 present associated

请注意,未定义的指针与不关联的(null)指针不同。您不能将未定义的指针用于任何事情,甚至不能查询其关联状态。

您可以对allocatables使用相同的内容,而不是指针。

你绝对不能拥有一个带有未定义地址的普通伪参数,这是语言所禁止的。

答案 1 :(得分:0)

为了使其工作(不像VladimirF那样使虚拟指针成为指针),您将需要购买(或编写)Fortran 2008编译器。

Fortran 2008将未分配的allocatable和disociated指针变量添加到与普通(不可分配,非指针)可选参数关联时被认为不存在的事物列表中。实际参数的等级必须与伪参数的等级匹配,但此功能可用于标量和数组。

如果您没有在您面前安装Fortran 2008编译器,那么您运气不好。没有实现此功能的编译器在面对未分配或分离的实际参数时可能会传递废话,并且它们对于标量和数组的行为可能会有所不同,因为这些通常在内部描述符方面处理不同。

(在您的示例代码中,您的语句Allocate(ArrB(n))只会泄漏内存。)