关于 IEEE 异常,通常需要关注以下问题:
用户例程的异常捕获以系统产生浮点异常信号开始。signal: floating-point exception的 UNIX 标准名称是 SIGFPE。出现异常时,SPARC 平台上的缺省情况是不产生 SIGFPE。要使系统产生 SIGFPE,必须先启用异常捕获,这通常通过对 ieee_handler() 的调用来完成。
要将函数作为异常处理程序建立,请将函数名称与要监视的异常的名称和要采取的操作一起传递给 ieee_handler()。一旦建立了处理程序,无论何时出现特定的浮点异常和调用指定的函数,都会产生 SIGFPE 信号。
ieee_handler() 的调用形式如下表所示:
表 6–4 ieee_handler (action , exception , handler) 的参数|
参数 |
类型 |
可能值 |
|---|---|---|
|
action |
character |
get、set 或 clear |
|
exception |
character |
invalid、division、overflow、underflow 或 inexact |
|
handler |
函数名 |
用户处理函数的名称或 SIGFPE_DEFAULT、SIGFPE_IGNORE 或 SIGFPE_ABORT |
|
返回值 |
integer |
0 =OK |
用 f95 编译的、调用 ieee_handler() 的 Fortran 95 例程还应该声明:
#include ’floatingpoint.h’
特殊参数 SIGFPE_DEFAULT、SIGFPE_IGNORE 和 SIGFPE_ABORT 定义在这些包含文件中,可用于更改与特定异常相应的程序行为:
|
SIGFPE_DEFAULT 或 SIGFPE_IGNORE |
出现指定异常时不采取任何操作。 |
|
SIGFPE_ABORT |
程序在异常时中止(可能会使用转储文件)。 |
异常处理程序采取的操作由您决定。但是,此例程必须是整型函数,且具有下面指定的三个参数:
handler_name( sig, sip, uap )
handler_name 是此整型函数的名称。
sig 是一个整数。
sip 是具有结构 siginfo 的记录。
未使用 uap。
示例:异常处理程序函数:
INTEGER FUNCTION hand( sig, sip, uap )
INTEGER sig, location
STRUCTURE /fault/
INTEGER address
INTEGER trapno
END STRUCTURE
STRUCTURE /siginfo/
INTEGER si_signo
INTEGER si_code
INTEGER si_errno
RECORD /fault/ fault
END STRUCTURE
RECORD /siginfo/ sip
location = sip.fault.address
... actions you take ...
END
|
此示例需要修改才能运行在 64 位 SPARC 体系结构上,方法是使用 INTEGER*8 替换每个 STRUCTURE 中的所有 INTEGER 声明。
如果由 ieee_handler() 启用的处理程序例程与此示例中一样,是用 Fortran 编写的,则此例程不能对其第一个参数 (sig) 进行任何引用。该第一个参数按值传递给此例程,并且只能作为 loc(sig) 进行引用。此值是信号编号。
下列示例展示如何创建处理程序例程来检测浮点异常。
SIGFPE 可在浮点异常出现的任何时间产生。检测到 SIGFPE 时,控制将传递给 myhandler 函数,该函数会立即中止。用 -g 编译,并使用 dbx 查找异常位置。
示例:定位异常(打印地址)并中止:
demo% cat LocExcHan.F
#include "floatingpoint.h"
EXTERNAL Exhandler
INTEGER Exhandler, i, ieee_handler
REAL:: r = 14.2 , s = 0.0 , t
C Detect division by zero
i = ieee_handler( ’set’, ’division’, Exhandler )
t = r/s
END
INTEGER FUNCTION Exhandler( sig, sip, uap)
INTEGER sig
STRUCTURE /fault/
INTEGER address
END STRUCTURE
STRUCTURE /siginfo/
INTEGER si_signo
INTEGER si_code
INTEGER si_errno
RECORD /fault/ fault
END STRUCTURE
RECORD /siginfo/ sip
WRITE (*,10) sip.si_signo, sip.si_code, sip.fault.address
10 FORMAT(’Signal ’,i4,’ code ’,i4,’ at hex address ’, Z8 )
Exhandler=1
CALL abort()
END
demo% f95 -g LocExcHan.F
demo% a.out
Signal 8 code 3 at hex address 11230
Abort
demo%
|
在 64 位 SPARC 环境中,请用 INTEGER*8 替换每个 STRUCTURE 中的 INTEGER 声明,用 i8 替换 i4 格式。(注意,该例接受 VAX Fortran STRUCTURE 语句,依靠的是 f95 编译器的扩展。)
大多数情况下,知道异常的实际地址并无太大用处,但对于 dbx 除外:
demo% dbx a.out
(dbx) stopi at 0x11230 Set breakpoint at address
(2) stopi at &MAIN+0x68
(dbx) run Run program
Running: a.out
(process id 18803)
stopped in MAIN at 0x11230
MAIN+0x68: fdivs %f3, %f2, %f2
(dbx) where Shows the line number of the exception
=>[1] MAIN(), line 7 in "LocExcHan.F"
(dbx) list 7 Displays the source code line
7 t = r/s
(dbx) cont Continue after breakpoint, enter handler routine
Signal 8 code 3 at hex address 11230
abort: called
signal ABRT (Abort) in _kill at 0xef6e18a4
_kill+0x8: bgeu _kill+0x30
Current function is exhandler
24 CALL abort()
(dbx) quit
demo%
|
当然,还有更容易的方法来确定引起错误的源码行。但是,本例确实足以展示异常处理的基本内容。