[英]Does exception handling exist in Fortran?
Is there any exception handling structure in Fortran, just like in Python? Fortran 中是否有任何异常处理结构,就像在 Python 中一样?
try:
print "Hello World"
except:
print "This is an error message!"
If it does not exist, what would be the easiest way to handle exceptions?如果它不存在,处理异常的最简单方法是什么?
Exceptions as such do not exist in Fortran, so no, there is no Exception handling. Fortran 中不存在这样的异常,所以不,没有异常处理。
But you can do something similar to Exception handling using Standard Fortran - there's even a paper on it Arjen Markus, "Exception handling in Fortran" .但是您可以使用标准 Fortran 执行类似于异常处理的操作 - 甚至有一篇关于它的论文Arjen Markus,“Fortran 中的异常处理” 。
The most common notation is to use an (integer) return variable indicating the error code:最常见的表示法是使用(整数)返回变量指示错误代码:
subroutine do_something(stat)
integer :: stat
print "Hello World"
stat = 0
end subroutine
and in the main program do并在主程序中做
call do_something(stat)
if (stat /= 0) print *,"This is an error message!"
There are other ways described in the paper such as defining a dedicated derived type for exceptions that is capable of also storing an error message.论文中还描述了其他方法,例如为异常定义专用的派生类型,该类型也能够存储错误消息。 The example mentioned there that gets closest to an Exception is using alternate returns for subroutines (not possible with functions, though):
那里提到的最接近 Exception 的示例是使用子例程的备用返回(尽管函数不可能):
subroutine do_something(stat, *)
integer :: stat
!...
! Some error occurred
if (error) return 1
end subroutine
and in the main program do并在主程序中做
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
Please note that the block construct requires a compiler compliant with Fortran 2008.请注意,块构造需要符合 Fortran 2008 的编译器。
I've never seen something like this out there, though :)我从来没有见过这样的东西,虽然:)
There are proposals (see Steve Lionel's comment below) to add exception handling to the next Fortran standard.有一些建议(请参阅下面的 Steve Lionel 的评论)将异常处理添加到下一个 Fortran 标准中。 See here for example: Exception handling - BCS Fortran Specialist Group
例如,请参见此处: 异常处理 - BCS Fortran 专家组
This has apparently a long history in Fortran (again see Steve's second comment below)这显然在 Fortran 中有着悠久的历史(再次参见下面史蒂夫的第二条评论)
Considering that a great deal of try-except
use cases are for I/O handling, you should know that all FORTRAN I/O functions have an ERR
specifier which points to a line label in the case an error happens.考虑到大量的
try-except
用例用于 I/O 处理,您应该知道所有 FORTRAN I/O 函数都有一个ERR
说明符,它在发生错误的情况下指向行标签。 For example:例如:
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'
of course one could replace the WRITE
executable with any other expression to achieve some form of except
functionality.当然,可以用任何其他表达式替换
WRITE
可执行文件以实现某种形式的except
功能。
Although this is not a proper "exception handling" I found practically useful the following subroutine虽然这不是一个正确的“异常处理”,但我发现以下子程序非常有用
SUBROUTINE RAISE_EXCEPTION(message)
INTEGER i
CHARACTER(LEN=*) message
PRINT *,message
i=1
i=1/(i-i)
ENDSUBROUTINE
that can be called when an error condition occurs, eg可以在发生错误情况时调用,例如
IF (var<0) CALL RAISE_EXCEPTION('Error: var should be positive!')
If the code is compiled with gfortran -ffpe-trap=zero
and -fbacktrace
options ( -fpe0
with ifort), the code will be stopped (because of the intentional division by zero in the subroutine) and a call stack will be printed.如果代码是用 gfortran
-ffpe-trap=zero
和-fbacktrace
选项( -fpe0
和 ifort)编译的,代码将被停止(因为在子例程中有意除以零)并打印调用堆栈。 Moreover, if you are debugging the code, the process won't be killed (even if the execution is halted) so you can explore variables, call stack etc. from inside the debugger.此外,如果您正在调试代码,则该进程不会被终止(即使执行已停止),因此您可以从调试器内部探索变量、调用堆栈等。
You could implement exception handling in Fortran 2003 without resorting to the alternate return statements in Arjen Markus's solution.您可以在 Fortran 2003 中实现异常处理,而无需求助于 Arjen Markus 解决方案中的备用 return 语句。 The idea is to use the final procedure of a type that stores the exceptions.
这个想法是使用存储异常的类型的最终过程。
A basic implementation is一个基本的实现是
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
and an example of raising an exception is引发异常的一个例子是
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
Now you can call this in several ways, assuming现在您可以通过多种方式调用它,假设
real :: sqrt_x
type(exception_stack_t), allocatable :: e
Regular call:定期调用:
call my_sqrt(-1.0,sqrt_x)
prints "EXCEPTION was not caught" , due to the my_e
local variable in my_sqrt
.版画“的异常没有被抓”,因
my_e
在局部变量my_sqrt
。
Calling without catching the exception:调用而不捕获异常:
call my_sqrt(-1.0,sqrt_x,e)
gives "EXCEPTION was not caught" once e
goes out of scope.一旦
e
超出范围,就会给出“未捕获异常” 。
Equivalent of a try-except block:相当于 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
which gives "ValueError for 'my_sqrt', but I'm continuing."这给出了“'my_sqrt'的ValueError,但我正在继续。”
This is different from using an error-indicating integer, because这与使用错误指示整数不同,因为
the caller does not have to remember to check the error status (the final
procedure will do that);调用者不必记住检查错误状态(
final
过程会这样做);
exception_stack_t
could store a list of raised exceptions, and it could be passed along procedures that call each other. exception_stack_t
可以存储引发异常的列表,并且可以沿着相互调用的过程传递。 Exceptions can be caught at any level.可以在任何级别捕获异常。
You could also define a whole hierarchy of exception types.您还可以定义异常类型的整个层次结构。
In principle it would be possible to create the same exception architecture as in Python, though it would be used with a very different syntax.原则上,可以创建与 Python 中相同的异常架构,尽管它会以非常不同的语法使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.