0
点赞
收藏
分享

微信扫一扫

C++学习------cfenv头文件的作用与源码分析01---类型定义

引言

cfenv是C++对C语言头文件fenv.h的封装,该头文件定义了一系列与浮点数运算环境相关的函数和宏定义,以及一些相关的结构体定义。它的作用主要是控制程序运行过程中浮点数运算的状态flag和控制模式,接下来我们来看看这个头文件的具体作用与实现原理。

注一:下面的源码参考android-12.0.0_r3中的源码,具体代码路径为:

​​www.aospxref.com/android-12.…​​

注二:贴近底层的代码实现通常都与具体的计算机体系结构相关,如:aarch64、arm、i386、x86_64等,文中以笔者的运行环境为主,主要讲述x86_64架构相关的代码实现与分析。

C++的封装逻辑

参考对应文件​​www.aospxref.com/android-12.…​​中的代码片段如下:

56 #include <__config>
57 #include <fenv.h>
58
59 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
60 #pragma GCC system_header
61 #endif
62
63 _LIBCPP_BEGIN_NAMESPACE_STD
64
65 using ::fenv_t;
66 using ::fexcept_t;
67
68 using ::feclearexcept;
69 using ::fegetexceptflag;
70 using ::feraiseexcept;
71 using ::fesetexceptflag;
72 using ::fetestexcept;
73 using ::fegetround;
74 using ::fesetround;
75 using ::fegetenv;
76 using ::feholdexcept;
77 using ::fesetenv;
78 using ::feupdateenv;
79
80 _LIBCPP_END_NAMESPACE_STD
81
82 #endif // _LIBCPP_CFENV

实际上这里做了两件事情,一是include了C语言的头文件“fenv.h”,二是,将头文件中全局的结构体、对应的函数都使用using语句修饰,保证在对应std 命名空间中都可以正常访问到。这便是C++对C头文件的封装,具体实现还是C语言头文件中的。

fenv.h的结构体定义与宏定义

我们先来看看定义部分:

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/include/fenv.h
34 #if defined(__aarch64__) || defined(__arm__)
35 #include <bits/fenv_arm.h>
36 #elif defined(__i386__)
37 #include <bits/fenv_x86.h>
38 #elif defined(__x86_64__)
39 #include <bits/fenv_x86_64.h>
40 #endif
...
42 __BEGIN_DECLS
//上面三个平台的函数定义
78 __END_DECLS
...
80 #if defined(__arm__)
81 #include <android/legacy_fenv_inlines_arm.h>
82 #endif

这里通过不同的平台宏进行区分,最后选择了不同的平台头文件,我们以__x86_64__进行分析,其它平台类似(注意,__arm__平台有些区别,其它三个平台的头文件只定义了结构体或者变量,所以需要在该文件中定义函数,但是__arm__平台在其头文件中同时定义了结构体变量和函数,就不需重复定义了)

FE_xxx 异常宏

定义了float运算的相关类别,按位进行标识。

  • FE_INVALID:非法参数异常
  • FE_DENORMAL:非法操作异常
  • FE_DIVBYZERO:除0异常
  • FE_OVERFLOW:上越界溢出异常
  • FE_UNDERFLOW:下越界溢出异常
  • FE_INEXACT:结果不精确异常
  • FE_ALL_EXCEPT:上面所有的异常,按位表示为0x3f

33  /*
34 * Each symbol representing a floating point exception expands to an integer
35 * constant expression with values, such that bitwise-inclusive ORs of _all
36 * combinations_ of the constants result in distinct values.
37 *
38 * We use such values that allow direct bitwise operations on FPU/SSE registers.
39 */
40 #define FE_INVALID 0x01
41 #define FE_DENORMAL 0x02
42 #define FE_DIVBYZERO 0x04
43 #define FE_OVERFLOW 0x08
44 #define FE_UNDERFLOW 0x10
45 #define FE_INEXACT 0x20
46
47 /*
48 * The following symbol is simply the bitwise-inclusive OR of all floating-point
49 * exception constants defined above.
50 */
51 #define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO | \
52 FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)

FE_xxx 浮点数舍入方向宏

定义了浮点数进行舍入时的方向,按位进行标识(因为浮点数有精度限制,现有的编码方式并不能表示所有的数,需要考虑进行舍入,即使用一个可以的编码来近似表示该浮点数)。

  • FE_TONEAREST:将x舍入为最接近x的值,有一半的case舍入为0
  • FE_DOWNWARD:将x舍入为不大于x的最大值
  • FE_UPWARD:将x舍入为不小于x的最小值
  • FE_TOWARDZERO:将x舍入为绝对值不大于x的最接近x的值

54  /*
55 * Each symbol representing the rounding direction, expands to an integer
56 * constant expression whose value is distinct non-negative value.
57 *
58 * We use such values that allow direct bitwise operations on FPU/SSE registers.
59 */
60 #define FE_TONEAREST 0x000
61 #define FE_DOWNWARD 0x400
62 #define FE_UPWARD 0x800
63 #define FE_TOWARDZERO 0xc00

fenv_t类型定义

该结构体实际上就是整个浮点数运算环境的定义,包括控制字、状态字、标志字等信息。

65  /*
66 * fenv_t represents the entire floating-point environment.
67 */
68 typedef struct {
69 struct {
70 __uint32_t __control; /* Control word register */
71 __uint32_t __status; /* Status word register */
72 __uint32_t __tag; /* Tag word register */
73 __uint32_t __others[4]; /* EIP, Pointer Selector, etc */
74 } __x87;
75 __uint32_t __mxcsr; /* Control, status register */
76 } fenv_t;

fexcept_t类型定义

异常状态类型信息,具体到函数使用时说明。

78  /*
79 * fexcept_t represents the floating-point status flags collectively, including
80 * any status the implementation associates with the flags.
81 *
82 * A floating-point status flag is a system variable whose value is set (but
83 * never cleared) when a floating-point exception is raised, which occurs as a
84 * side effect of exceptional floating-point arithmetic to provide auxiliary
85 * information.
86 *
87 * A floating-point control mode is a system variable whose value may be set by
88 * the user to affect the subsequent behavior of floating-point arithmetic.
89 */
90 typedef __uint32_t fexcept_t;

fenv.h的变量定义

定义了一个全局只读变量__fe_dfl_env,即我们上面说的fenv_t结构体,保存浮点数运算的相关环境设置信息;同时定义了一个获取该变量地址的宏FE_DFL_ENV,使用取地址符,返回变量地址。

67  /*
68 * The following constant represents the default floating-point environment
69 * (that is, the one installed at program startup) and has type pointer to
70 * const-qualified fenv_t.
71 *
72 * It can be used as an argument to the functions that manage the floating-point
73 * environment, namely fesetenv() and feupdateenv().
74 */
75 extern const fenv_t __fe_dfl_env;
76 #define FE_DFL_ENV (&__fe_dfl_env)

函数定义及源码解析后文分享

举报

相关推荐

0 条评论