当前位置: C语言 -- 标准库 -- <tgmath.h>

<tgmath.h>头文件

<tgmath.h>头文件包括<math.h>头文件和<complex.h>头文件,并定义了一些泛型宏。

如果实现支持ISO/IEC 9899:2024标准,宏__STDC_VERSION_TGMATH_H__将扩展为值为202311L的整数常量表达式。

<math.h>头文件和<complex.h>头文件中的函数与<tgmath.h>头文件中的泛型宏之间存在多对一对应关系(many-to-one correspondence)。使用泛型宏会调用对应函数,函数类型由泛型形参(generic parameters)对应的实参类型决定。如果实参类型与所选函数的形参类型不兼容,其行为是未定义的。与标准库中的其它函数式宏一样,为使对应的普通函数可用,<tgmath.h>头文件中的泛型宏可以被抑制。


<math.h>头文件、<complex.h>头文件中无f(float)或者l(long double)后缀的函数中,一些函数存在一个或者多个double类型的形参;这些函数(<math.h>头文件中将结果舍入到更窄类型的函数以及modf函数除外。)都存在一个对应的泛型宏(type-generic macro)。函数概要(function synopsis)中对应实数类型为double类型的形参为泛型形参(generic parameters)。

某些十进制浮点类型函数不存在不带后缀的对应版本。在这些存在d64后缀的函数中,有些函数存在一个或者多个类型为_Decimal64类型的形参。对于这类函数(decodedecd64、encodedecd64、decodebind64、encodebind64函数除外。)都存在一个对应的泛型宏。函数概要(function synopsis)中对应实数类型为_Decimal64类型的形参为泛型形参(generic parameters)。


泛型宏泛型形参的对应实参中,如果某个实参是标准浮点类型(standard floating type),另一个实参是十进制浮点类型(decimal floating type),其行为是未定义的。

<math.h>头文件中将结果舍入到更窄类型的函数宏除外,使用泛型宏会调用一个函数,该函数的泛型形参对应的实数类型由实参类型按以下方式确定:

- 如果任一实参为十进制浮点类型,整数类型实参视为_Decimal64类型,否则视为double类型。

- 如果函数仅存在一个泛型形参,所确定类型是该泛型形参的对应实参的类型;即对于只有一个泛型形参的泛型宏,实参是什么类型,就调用对应类型的函数。

- 如果函数存在两个泛型形参,所确定类型是这两个泛型形参的对应实参执行常用算术转换(usual arithmetic conversions)后所得结果的类型;即对于存在两个泛型形参的泛型宏,先根据常用算术转换规则将两个实参统一成一个共同类型,然后根据共同类型调用对应的函数。

- 如果函数存在三个及三个以上泛型形参,所确定类型通过反复执行常用算术转换得到:首先对前两个泛型形参的对应实参执行常用算术转换,然后将结果类型与下一个泛型形参的对应实参执行常用算术转换,依此类推,直至对所有泛型形参的对应实参都执行完常用算术转换为止。也就是说,对于存在三个及三个以上泛型形参的泛型宏,从左到右逐个统一类型,先将前两个统一成一个共同类型,然后用这个共同类型和第三个统一......直至全部处理完,最后根据最终得到的类型调用对应的函数。


以泛型宏fabs为例:

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
/*泛型宏fabs范例*/

#include <stdio.h>
#include <tgmath.h>

/*判断数据类型的宏。*/
#define TYPE(x) _Generic((x),  \
                         float:"float type",  \
                         double:"double type",  \
                         long double:"long double type",  \
                         default:"unknown type"  \
                         )

int main(void)
{
    printf("TYPE(fabs(1)): %s\n", TYPE(fabs(1)));
    printf("TYPE(fabs(1.0)): %s\n", TYPE(fabs(1.0)));
    printf("TYPE(fabs(1.0f)): %s\n", TYPE(fabs(1.0f)));
    printf("TYPE(fabs(1.0L)): %s\n", TYPE(fabs(1.0L)));
    
    return 0;
}


输出:

TYPE(fabs(1)): double type

TYPE(fabs(1.0)): double type

TYPE(fabs(1.0f)): float type

TYPE(fabs(1.0L)): long double type


如果根据泛型形参的对应实参所确定的函数在<math.h>头文件和<complex.h>头文件中均未定义,其行为是未定义的。

对于<math.h>头文件中无后缀的函数以及<complex.h>头文件中的同名函数(存在字母前缀c。),对应的泛型宏是相同的,与<math.h>头文件中的那个函数同名。泛型宏fabs是个例外,其对应的函数分别是fabs(<math.h>头文件)和cabs(<complex.h>头文件)。

上述函数与泛型宏的对应关系如下表所示:

泛型宏 <math.h>头文件中函数 <complex.h>头文件中函数
float double long double _Decimal32 _Decimal64 _Decimal128 float double long double
acos acosf acos acosl acosd32 acosd64 acosd128 cacosf cacos cacosl
asin asinf asin asinl asind32 asind64 asind128 casinf casin casinl
atan atanf atan atanl atand32 atand64 atand128 catanf catan catanl
acosh acoshf acosh acoshl acoshd32 acoshd64 acoshd128 cacoshf cacosh cacoshl
asinh asinhf asinh asinhl asinhd32 asinhd64 asinhd128 casinhf casinh casinhl
atanh atanhf atanh atanhl atanhd32 atanhd64 atanhd128 catanhf catanh catanhl
cos cosf cos cosl cosd32 cosd64 cosd128 ccosf ccos ccosl
sin sinf sin sinl sind32 sind64 sind128 csinf csin csinl
tan tanf tan tanl tand32 tand64 tand128 ctanf ctan ctanl
cosh coshf cosh coshl coshd32 coshd64 coshd128 ccoshf ccosh ccoshl
sinh sinhf sinh sinhl sinhd32 sinhd64 sinhd128 csinhf csinh csinhl
tanh tanhf tanh tanhl tanhd32 tanhd64 tanhd128 ctanhf ctanh ctanhl
exp expf exp expl expd32 expd64 expd128 cexpf cexp cexpl
log logf log logl logd32 logd64 logd128 clogf clog clogl
pow powf pow powl powd32 powd64 powd128 cpowf cpow cpowl
sqrt sqrtf sqrt sqrtl sqrtd32 sqrtd64 sqrtd128 csqrtf csqrt csqrtl
fabs fabsf fabs fabsl fabsd32 fabsd64 fabsd128 cabsf cabs cabsl

如果泛型宏中至少一个泛型形参对应的实参是复数,将调用复数函数;如果泛型宏中没有泛型形参对应的实参是复数,将调用实数函数。


以泛型宏sin为例:

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
/*泛型宏sin范例*/

#include <stdio.h>
#include <tgmath.h>

int main(void)
{
    double numberReal;
    double complex numberComplex;

    /*调用<math.h>头文件中的sin函数。*/
    numberReal = sin(1.0);
    printf("sin(1.0) = %.2f\n", numberReal);

    /*调用<complex.h>头文件中的csin函数。*/
    numberComplex = sin(1.0+1.0i);
    printf("sin(1.0+1.0i) = %.2f%+.2fi\n",creal(numberComplex), cimag(numberComplex));
 
    return 0;
}


输出:

sin(1.0) = 0.84

sin(1.0+1.0i) = 1.30+0.63i