在 Fortran 中处理多个退出点的最佳方法

问题描述 投票:0回答:1

我有一个读取文件的 Fortran 代码(如果您对背景感到好奇,请参阅如何在使用 Python 读取时安全地检查 Fortran 文件是否存在?)。由于此代码是从 Python 调用的,因此我需要处理所有或大多数 IO 错误,因为我不希望我的 Python 代码在没有合理错误消息的情况下崩溃。因此我这样编辑了 Fortran 代码:

  subroutine read_params(filename, params, ierr)
  implicit none
  ! Argument Declarations !
  character(len=*), intent(in) :: filename
  integer, dimension(4), intent(out) :: params
  integer, intent(out) :: ierr
  ! Variable Declarations
  integer :: i, iounit, ios
  character(len=:), allocatable :: errmsg

  iounit = 1
  ierr = 0 ! Initialize error code
  allocate(character(len=256+len(filename)) :: errmsg)
  open(unit=iounit, status="old", file=filename, form="unformatted", iostat=ios, iomsg=errmsg)
  call check_for_io_errors(ios, "open", ierr, errmsg)
  if (ierr /= 0) then
      close(iounit)
      return
  end if
  read(iounit, *, iostat=ios, iomsg=errmsg) (params(i), i=1, 4)
  call check_for_io_errors(ios, "read", ierr, errmsg)
  if (ierr /= 0) then
      close(iounit)
      return
  end if
  close(iounit)

  end subroutine read_params

如您所见,子例程有多个退出点,并且有一些代码重复。或者,我可以这样做

      subroutine read_params(filename, params, ierr)
      implicit none
      ! Argument Declarations !
      character(len=*), intent(in) :: filename
      integer, dimension(4), intent(out) :: params
      integer, intent(out) :: ierr
      ! Variable Declarations
      integer :: i, iounit, ios
      character(len=:), allocatable :: errmsg

      iounit = 1
      ierr = 0 ! Initialize error code
      allocate(character(len=256+len(filename)) :: errmsg)
      open(unit=iounit, status="old", file=filename, form="unformatted", iostat=ios, iomsg=errmsg)
      call check_for_io_errors(ios, "open", ierr, errmsg)
      if (ierr /= 0) then
          goto 10
      end if
      read(iounit, *, iostat=ios, iomsg=errmsg) (params(i), i=1, 4)
      call check_for_io_errors(ios, "read", ierr, errmsg)
      if (ierr /= 0) then
          goto 10
      end if
10    close(iounit)

      end subroutine read_params

它使用了可怕的

goto
语句。在 Fortran ≤ 2003 中执行此操作的首选方法是什么?另外,如果您有任何其他改进代码的建议,请随时告诉我。

PS,可能没有必要回答主要问题,但这里是子例程的源代码

check_for_io_errors
,以防您好奇:

  subroutine check_for_io_errors(ios, operation, ierr, errmsg)
  implicit none
  ! Argument Declarations !
  integer, intent(in) :: ios
  character(len=*), intent(in) :: operation
  integer, intent(out) :: ierr
  character(len=*), intent(in) :: errmsg

  if (ios /= 0) then
      if (operation == "open") then
          ierr = -1
          print *, "Error opening file"
          print *, "Error message: " // trim(errmsg)
      else if (operation == "read") then
          ierr = -2
          print *, "Error reading file"
          print *, "Error message: " // trim(errmsg)
      else if (operation == "write") then
          ierr = -3
          print *, "Error writing file"
          print *, "Error message: " // trim(errmsg)
      end if
  end if

  end subroutine check
io fortran
1个回答
0
投票

合理使用

goto
,就像这里一样,对我来说看起来不错。与
return
解决方案相比,优点是您不必重复
close(iounit)
语句(好吧,这只是一个语句,但想象一下如果您有多个语句......)。

正如评论中所指出的,

block
控制结构提供了一种可能更结构化的方式:

block
   ...
   if (ierr /= 0) exit
   ...
   if (ierr /= 0) exit
   ...
end block
close(iounit)

如果您的编译器不允许使用它,您可以通过“无限 do 循环”实现类似的效果(只是不要忘记最后的

exit
!):

do
   ...
   if (ierr /= 0) exit
   ...
   if (ierr /= 0) exit
   ...
   exit
end do
close(iounit)
© www.soinside.com 2019 - 2024. All rights reserved.