Fortran中是否有任何异常处理结构,就像在Python中一样?
try:
print "Hello World"
except:
print "This is an error message!"
如果它不存在,处理异常的最简单方法是什么?
答案 0 :(得分:11)
Fortran中不存在异常,所以不,没有异常处理。
但你可以做类似于使用标准Fortran的异常处理 - 甚至还有一篇论文Arjen Markus, "Exception handling in Fortran"。
最常见的表示法是使用指示错误代码的(整数)返回变量:
subroutine do_something(stat)
integer :: stat
print "Hello World"
stat = 0
end subroutine
并在主程序中执行
call do_something(stat)
if (stat /= 0) print *,"This is an error message!"
本文中描述了其他方法,例如为异常定义专用派生类型,该类型也能够存储错误消息。 那里提到的最接近Exception的例子是使用子例程的备用返回(但不能用函数):
subroutine do_something(stat, *)
integer :: stat
!...
! Some error occurred
if (error) return 1
end subroutine
并在主程序中执行
try: block
call do_something(stat, *100)
exit try ! Exit the try block in case of normal execution
100 continue ! Jump here in case of an error
print *,"This is an error message!"
end block try
请注意,块构造需要符合Fortran 2008的编译器。
我从来没有见过这样的东西,但是:)
答案 1 :(得分:3)
有一些建议(请参阅下面的Steve Lionel评论)将异常处理添加到下一个Fortran标准中。例如:Exception handling - BCS Fortran Specialist Group
这在Fortran中显然有很长的历史(再次见到Steve的第二条评论)
答案 2 :(得分:2)
考虑到大量try-except
用例用于I / O处理,您应该知道所有FORTRAN I / O函数都有一个ERR
说明符,在该情况下指向行标签发生错误。例如:
C2345678
READ( UNIT=5, FMT=10, ERR=30, IOSTAT=N ) X
10 FORMAT(I5)
WRITE( UNIT=6, FMT=20, ERR=30, IOSTAT=N ) X
20 FORMAT(I5)
30 WRITE( *, * ) 'I/O error # ', N, ', on 1'
当然可以用任何其他表达式替换WRITE
可执行文件,以实现某种形式的except
功能。
答案 3 :(得分:1)
您可以在Fortran 2003中实现异常处理 而不求助于Arjen Markus解决方案中的备用return语句。 想法是使用存储异常的类型的最终过程。
一个基本的实现是
module exception_mod
implicit none
type exception_stack_t
! should contain a list of raised exceptions,
! but keep it simple for this example
logical :: raised = .false.
contains
final :: error_if_uncaught
end type
contains
subroutine raise(e)
! should take an exception as a dummy argument, and add it to the stack.
type(exception_stack_t), intent(out) :: e
e%raised = .true.
end subroutine
logical function catch(e) result(was_raised)
! should catch a particular type of exception that is passed to this procedure
type(exception_stack_t), intent(inout) :: e
was_raised = e%raised
e%raised = .false.
end function
subroutine error_if_uncaught(this)
type(exception_stack_t), intent(in) :: this
if (this%raised) error stop "EXCEPTION was not caught"
end subroutine
end module
举一个异常的例子是
subroutine my_sqrt(x,sqrt_x,e)
real, intent(in) :: x
real, intent(out) :: sqrt_x
type(exception_stack_t), optional, allocatable, intent(inout) :: e
type(exception_stack_t), allocatable :: my_e
if (x < 0) then
allocate(my_e)
call raise(my_e)
! should push exception `my_e` to the stack `e`
if (present(e)) call move_alloc(my_e, e)
return
endif
sqrt_x = sqrt(x)
end subroutine
现在您可以通过多种方式调用此命令, 假设
real :: sqrt_x
type(exception_stack_t), allocatable :: e
常规通话:
call my_sqrt(-1.0,sqrt_x)
打印“未捕获到EXCEPTION” ,
由于my_e
中的my_sqrt
局部变量。
在不捕获异常的情况下进行调用:
call my_sqrt(-1.0,sqrt_x,e)
给出了“未捕获到例外”
一旦e
超出范围。
等效于try-except块:
call my_sqrt(-1.0,sqrt_x,e)
if (catch(e)) then
print "(a)", "ValueError for 'my_sqrt', but I'm continuing."
else
print "(a,f0.10)", "sqrt = ", sqrt_x
endif
给出 “'my_sqrt'的ValueError,但我继续。”
这与使用错误指示整数不同, 因为
呼叫者不必记住检查错误状态
(final
过程将执行此操作);
exception_stack_t
可以存储引发的异常列表,
并且可以通过相互调用的过程来传递。
可以在任何级别捕获异常。
您还可以定义异常类型的整个层次结构。
原则上,可以创建与Python中相同的异常体系结构, 尽管它会以非常不同的语法使用。
答案 4 :(得分:0)
尽管这不是适当的“异常处理”,但我发现以下子例程实际上很有用
SUBROUTINE RAISE_EXCEPTION(message)
INTEGER i
CHARACTER(LEN=*) message
PRINT *,message
i=1
i=1/(i-i)
ENDSUBROUTINE
发生错误情况时可以调用的
IF (var<0) CALL RAISE_EXCEPTION('Error: var should be positive!')
如果代码是使用gfortran -ffpe-trap=zero
和-fbacktrace
选项(带有ifort的-fpe0
)编译的,则代码将停止运行(因为在子例程中有意除以零),并且调用堆栈将被打印。此外,如果您要调试代码,则该进程将不会被杀死(即使执行被暂停),因此您可以从调试器内部探索变量,调用堆栈等。