我有一个读取文件的 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
合理使用
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)