国际访客建议访问 Primers 编程伙伴 国际版站点 > C 教程 > fenv.h 以获得更好的体验。

# C 语言标准库头文件 fenv.h

请查看 C 语言标准库头文件列表 了解更多相关 API。

这个头文件提供 浮点数环境 的相关功能,例如浮点异常处理、舍入方向控制等。

需要链接数学库,例如在 gcc 中需要添加 -lm 链接选项。

浮点环境功能依赖于硬件和编译器的具体实现,可能需要手动开启:

  • 通过 #pragma STDC FENV_ACCESS ON 预处理指令可以开启浮点环境功能。

  • 通过 #pragma STDC FENV_ACCESS OFF 预处理指令可以关闭浮点环境功能。

  • 部分硬件或编译器可能不支持。

# 示例

#include <stdio.h>
#include <fenv.h>
#include <math.h>
#include <errno.h>

void show_exceptions(void) {
    printf("当前浮点异常状态: ");
    if (fetestexcept(FE_ALL_EXCEPT) == 0) {
        printf("无异常\n");
        return;
    }
    
    if (fetestexcept(FE_DIVBYZERO)) printf("除零异常 ");
    if (fetestexcept(FE_INVALID))   printf("无效操作异常 ");
    if (fetestexcept(FE_OVERFLOW))  printf("上溢异常 ");
    if (fetestexcept(FE_UNDERFLOW)) printf("下溢异常 ");
    if (fetestexcept(FE_INEXACT))   printf("不精确结果异常 ");
    printf("\n");
}

void show_rounding_mode(void) {
    printf("当前舍入模式: ");
    switch (fegetround()) {
        case FE_TONEAREST:  printf("四舍五入\n"); break;
        case FE_DOWNWARD:   printf("向负无穷方向舍入\n"); break;
        case FE_UPWARD:     printf("向正无穷方向舍入\n"); break;
        case FE_TOWARDZERO: printf("向零舍入\n"); break;
        default:            printf("未知模式\n");
    }
}

int main(void) {
    // 1. 显示初始浮点环境
    printf("=== 初始浮点环境 ===\n");
    show_exceptions();
    show_rounding_mode();
    printf("\n");
    
    // 2. 触发浮点异常示例
    printf("=== 触发浮点异常 ===\n");
    feclearexcept(FE_ALL_EXCEPT);  // 清除所有异常标志
    
    // 除零异常
    double x = 1.0, y = 0.0;
    double z = x / y;
    printf("1.0 / 0.0 = %f\n", z);
    show_exceptions();
    
    // 无效操作异常
    double a = sqrt(-1.0);
    printf("sqrt(-1.0) = %f\n", a);
    show_exceptions();
    printf("\n");
    
    // 3. 舍入模式控制示例
    printf("=== 舍入模式控制 ===\n");
    fesetround(FE_DOWNWARD);  // 设置为向负无穷舍入
    show_rounding_mode();
    
    double num = 1.75;
    printf("1.75 舍入后: %f\n", rint(num));
    
    fesetround(FE_UPWARD);    // 设置为向正无穷舍入
    show_rounding_mode();
    printf("1.75 舍入后: %f\n", rint(num));
    
    fesetround(FE_TONEAREST); // 恢复默认舍入模式
    printf("\n");
    
    // 4. 浮点环境保存与恢复
    printf("=== 环境保存与恢复 ===\n");
    fenv_t env;
    fegetenv(&env);  // 保存当前环境
    
    // 修改环境
    fesetround(FE_TOWARDZERO);
    feclearexcept(FE_ALL_EXCEPT);
    
    printf("修改后的环境:\n");
    show_rounding_mode();
    show_exceptions();
    
    fesetenv(&env);  // 恢复原始环境
    printf("\n恢复后的环境:\n");
    show_rounding_mode();
    show_exceptions();
    
    return 0;
}

运行结果:

user@host:~ $ gcc main.c -lm
user@host:~ $ ./a.out
=== 初始浮点环境 ===
当前浮点异常状态: 无异常
当前舍入模式: 四舍五入

=== 触发浮点异常 ===
1.0 / 0.0 = inf
当前浮点异常状态: 除零异常
sqrt(-1.0) = -nan
当前浮点异常状态: 除零异常 无效操作异常

=== 舍入模式控制 ===
当前舍入模式: 向负无穷方向舍入
1.75 舍入后: 1.000000
当前舍入模式: 向正无穷方向舍入
1.75 舍入后: 2.000000

=== 环境保存与恢复 ===
修改后的环境:
当前舍入模式: 向零舍入
当前浮点异常状态: 无异常

恢复后的环境:
当前舍入模式: 四舍五入
当前浮点异常状态: 除零异常 无效操作异常 不精确结果异常

# 类型

类型 标准 说明
fenv_t C99 表示整个浮点环境的类型
fexcept_t C99 表示整个浮点异常标志的类型

# 函数

函数 标准 说明
feclearexcep C99 清除指定的浮点异常
fetestexcept C99 检查指定的浮点异常
feraiseexcept C99 产生指定的浮点异常
fegetexceptflag C99 整体获取浮点异常标志
fesetexceptflag C99 整体设置浮点异常标志
fegetround C99 获取舍入方向
fesetround C99 设置舍入方向
fegetenv C99 获取浮点环境
fesetenv C99 设置浮点环境
feholdexcept C99 保存浮点环境并清空浮点异常
feupdateenv C99 恢复浮点环境并触发浮点异常

#

标准 说明
FE_DFL_ENV C99 指向默认浮点环境的指针
浮点数异常宏 标准 说明
FE_ALL_EXCEPT C99 所有支持的浮点异常的按位或
FE_DIVBYZERO C99 浮点运算中发生了极点错误
FE_INEXACT C99 结果不精确:需要进行舍入才能存储
FE_INVALID C99 浮点运算中发生了域错误
FE_OVERFLOW C99 浮点运算的结果太大而溢出
FE_UNDERFLOW C99 浮点运算的结果太小而损失精度
浮点数舍入方向宏 !id:custom-anchor-nearbyint 标准 说明
FE_DOWNWARD C99 向负无穷方向舍入
FE_TONEAREST C99 四舍五入到最接近的可表示值
FE_TOWARDZERO C99 向零舍入
FE_UPWARD C99 向正无穷方向舍入

# 推荐阅读

本文 更新于: 2025-11-27 09:38:06 创建于: 2025-11-27 09:38:06