本节介绍了 C99 中的 <fenv.h> 浮点环境函数。在 Oracle Solaris 10 操作系统中,这些函数位于 libm 中。它们提供很多与 ieee_flags 函数相同的功能,但它们使用的 C 接口更普通;因为它们是由 C99 定义的,所以它们具有更高的可移植性。
fenv.h 文件为 5 个 IEEE 浮点异常标志中的每一个标志都定义了宏:FE_INEXACT、FE_UNDERFLOW、FE_OVERFLOW、FE_DIVBYZERO 和 FE_INVALID。此外,将宏 FE_ALL_EXCEPT 定义为所有 5 个标志宏进行按位“或”运算。在以下说明中,excepts 参数可以是 5 个标志宏中任何一个宏的按位“或”运算或者值 FE_ALL_EXCEPT。对于 fegetexceptflag 和 fesetexceptflag 函数,flagp 参数必须是指向类型为 fexcept_t 的对象的指针。这种类型是在 fenv.h 中定义的。
C99 定义了下表中的异常标志函数:
|
feclearexcept 函数清除指定的标志。fetestexcept 函数返回与设置的 excepts 参数指定的标志子集对应的宏值的按位“或”运算结果。例如,如果当前设置的标志只有不精确、下溢和除以零,则以下指令将 i 设置为 FE_DIVBYZERO。
i = fetestexcept(FE_INVALID | FE_DIVBYZERO);
如果启用任何指定异常的陷阱,则 feraiseexcept 函数会导致一个陷阱。否则,它只设置相应的标志。有关异常陷阱的更多信息,请参见异常和异常处理。
fegetexceptflag 和 fesetexceptflag 函数提供了一种简便的方法暂时保存某些标志的状态,并在以后恢复它们。特别地,fesetexceptflag 函数并不导致陷阱;它只恢复指定标志的值。
fenv.h 文件为 4 个 IEEE 舍入方向模式中的每一个模式定义了宏:FE_TONEAREST、FE_UPWARD(向正无穷大舍入)、FE_DOWNWARD(向负无穷大舍入)和 FE_TOWARDZERO。C99 定义了两个函数以控制舍入方向模式:fesetround 将当前的舍入方向设置为其参数指定的方向(必须是以上 4 个宏之一),而 fegetround 返回对应于当前舍入方向的宏值。
在基于 x86 的系统上,fenv.h 文件为 3 个舍入精度模式中的每一个模式定义宏:FE_FLTPREC(单精度)、FE_DBLPREC(双精度)和 FE_LDBLPREC(扩展双精度)。虽然它们不是 C99 的一部分,但 x86 上的 libm 提供了两个函数来控制舍入精度模式:fesetprec 将当前的舍入精度设置为其参数指定的精度(必须是以上 3 个宏之一),而 fegetprec 返回对应于当前舍入精度的宏值。
fenv.h 文件定义了数据类型 fenv_t,它表示整个浮点环境,包括异常标志、舍入控制模式、异常处理模式和(在 SPARC 上的)非标准模式。在以下说明中,envp 参数必须是指向类型为 fenv_t 的对象的指针。
C99 定义 4 个函数以处理浮点环境。libm 提供的一个附加函数在多线程程序中非常有用。下表概要介绍了这些函数:
|
fegetenv 和 fesetenv 函数分别用来保存和恢复浮点环境。fesetenv 的参数可以是指向以前通过调用 fegetenv 或 feholdexcept 保存的环境的指针,或者在 fenv.h 中定义的常量 FE_DFL_ENV。后者表示缺省环境,即清除所有异常标志、舍入到最接近的值以及在基于 x86 的系统上舍入到扩展双精度、不间断的异常处理模式(即禁用陷阱)以及禁用非标准的模式。
feholdexcept 函数会保存当前的环境,然后清除所有异常标志并为所有异常建立不间断的异常处理模式。feupdateenv 函数恢复保存的环境(可通过调用 fegetenv 或 feholdexcept 或常量 FE_DFL_ENV),然后引发在先前环境中设置其标志的异常。如果恢复的环境为其中的任何异常启用了陷阱,则会发生陷阱;否则,设置这些标志。可结合使用这两个函数,使子例程调用相对于异常为原子操作,如以下代码样例所示:
#include <fenv.h> void myfunc(...) { fenv_t env; /* save the environment, clear flags, and disable traps */ feholdexcept(&env); /* do a computation that may incur exceptions */ ... /* check for spurious exceptions */ if (fetestexcept(...)) { /* handle them appropriately and clear their flags */ ... feclearexcept(...); } /* restore the environment and raise relevant exceptions */ feupdateenv(&env); }
fex_merge_flags 函数对当前环境和保存环境中的异常标志执行逻辑 OR 运算,而不调用任何陷阱。可以在多线程程序中使用此函数,在父线程中保存有关子线程中的计算引发的标志的信息。有关显示 fex_merge_flags 用法的示例,请参见示例。