簡體   English   中英

fortran:檢測作為虛擬參數傳遞的空指針

[英]fortran: Detecting null-pointer passed as dummy argument

我想從子程序內部檢測到通過intent(in)傳遞的虛擬參數實際上是一個 null 指針:

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

令我驚訝的是它適用於 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
$ 

有任何想法嗎? 謝謝!

片段

  iPtr => null()
  print *, "passing iPtr => null()"
  call pointer_detect(iPtr)

違反了 Fortran 標准並使您的程序無效(Fortran 2008,25.5.2.3):

除了對內在查詢函數的引用外,對應於非可選非指針偽參數的指針實際參數應是與目標相關聯的指針。

非內在過程的偽參數既不是可選的,也不是指針。

避免這個問題的責任完全是程序員的,編譯器沒有義務為你檢測這個損壞的代碼。

但是,如果被問到(通常在運行時),編譯器很可能能夠檢測到此類錯誤:

At line 19 of file brokenpointer.f90
Fortran runtime error: Pointer actual argument 'iptr' is not associated

在使用 gfortran 和編譯選項-fcheck=pointer時是 output ,或者

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

使用 ifort 的-check pointers

程序員不能在過程本身內可靠地進行類似的檢查,因為 Fortran 編譯器沒有義務尊重以這種方式違反規則的程序員。

在這里查看程序的工作,例如:

      iPtr => iVal
      if (associated(iPtr)) then

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

一個非指針的、不可分配的、可選的偽參數如果與一個分離的指針實際參數相關聯,將被視為不存在。

但是請注意,如果iPtr的關聯狀態未定義,這對您沒有幫助。 什么都不會。

如果指針為 null,則call pointer_detect(iPtr)不符合標准。例程pointer_detect()的命名很糟糕,因為它無法檢測到有關原始指針的任何信息,而原始指針根本沒有傳遞:虛擬參數不是指針,所以在調用時,編譯器將傳遞iPtr的目標地址,而不是iPtr本身。 但是如果iPtr是 null 那么它沒有目標:行為未定義。

未定義的行為是未定義的。 或說不可預測。 它可能會崩潰,或者 output 不可預測的值,等等......這種違反標准的行為在編譯時無法真正檢測到,編譯器也不需要這樣做。 不過,gfortran 可能具有啟用運行時檢測的編譯選項(與任何其他運行時檢查一樣,會降低性能)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM