fortran:检测作为虚拟参数传递的空指针

Rou*_*oux 3 standards fortran pointers

我想从子例程内部检测到传递的虚拟参数intent(in)实际上是空指针:

program testPTR
  
implicit none
  
integer, target :: ii
integer, pointer :: iPtr
  
  iPtr => ii
  iPtr = 2
  
  print *, "passing ii"
  call pointer_detect(ii)
  
  print *, "passing iPtr"
  call pointer_detect(iPtr)
  
  iPtr => null()
  print *, "passing iPtr => null()"
  call pointer_detect(iPtr)
  
contains
                                                                                                                                                                      
  subroutine pointer_detect(iVal)
      implicit none
      integer, intent(in), target :: iVal
      integer, pointer :: iPtr
      character(len = *), parameter :: sub_name = 'pointer_detect'
    
      iPtr => iVal
      if (associated(iPtr)) then
        print *, "Pointer associated. Val=", iVal, ", iPtr = ", iPtr
      else
        print *, "Pointer not associated. Val=", iVal, ", iPtr = ", iPtr
       endif
  
  end subroutine pointer_detect
  
end program
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是它适用于 gfortran-9 和 gfortran-12。不过我有几个问题:

  1. 支票的合法性、可移植性和 Fortran 风格如何?
  2. 由于某种原因,它在最后一次打印时不会出现段错误,而是打印零并干净地退出:
$ gfortan test.f90
$ ./a.out && echo ok
passing ii
 Pointer associated. Val=           2 , iPtr =            2
 passing iPtr
 Pointer associated. Val=           2 , iPtr =            2
 passing iPtr => null()
 Pointer not associated. Val=           0 , iPtr =            0
ok
$ 
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?谢谢你!

fra*_*lus 6

片段

  iPtr => null()
  print *, "passing iPtr => null()"
  call pointer_detect(iPtr)
Run Code Online (Sandbox Code Playgroud)

违反了 Fortran 标准并使您的程序无效(Fortran 2008, 25.5.2.3):

除了对内部查询函数的引用之外,与非可选非指针虚拟参数相对应的指针实际参数应是与目标关联的指针。

非内在过程的虚拟参数既不是可选的,也不是指针。

避免这个问题的责任完全在于程序员,编译器没有责任为您检测这个损坏的代码。

但是,如果被要求,编译器很可能能够检测到此类错误(通常在运行时):

At line 19 of file brokenpointer.f90
Fortran runtime error: Pointer actual argument 'iptr' is not associated
Run Code Online (Sandbox Code Playgroud)

是使用 gfortran 和编译选项时的输出-fcheck=pointer,或者

forrtl: severe (408): fort: (7): Attempt to use pointer IPTR when it is not associated with a target
Run Code Online (Sandbox Code Playgroud)

与 ifort 的-check pointers.

程序员无法在过程本身内可靠地执行类似的检查,因为 Fortran 编译器没有义务尊重以这种方式违反规则的程序员。

看看这里的过程的努力,例如:

      iPtr => iVal
      if (associated(iPtr)) then
Run Code Online (Sandbox Code Playgroud)

iVal不是指针,因此iPtr在该指针赋值中与该变量相关联。编译器可以假设您没有违反 Fortran 规则,因此iptr是关联的并且测试条件始终为真。没有有效的 Fortran 程序可以使该测试条件解析为 false。

然而,并非所有希望都破灭了。我引用的标准中的文本说的是“非指针”以外的东西:它说的是“非可选”。如果iVal是可选使用PRESENT()

  subroutine pointer_detect(iVal)
      implicit none
      integer, intent(in), optional :: iVal
      character(len = *), parameter :: sub_name = 'pointer_detect'
    
      if (present(iVal)) then
        print *, "Actual argument pointer was associated. Val=", iVal
      else
        print *, "Actual argument pointer was not associated."
      endif
  
  end subroutine pointer_detect
Run Code Online (Sandbox Code Playgroud)

如果与不关联的指针实际参数关联,则非指针、不可分配、可选虚拟参数将被视为不存在。

iPtr但请注意,如果是未定义的关联状态,这对您没有帮助。什么都不会。