__tg_promote在tgmath.h中做什么

What does __tg_promote do in tgmath.h

本文关键字:什么 tgmath tg promote      更新时间:2023-10-16

我正在查看tgmath.h并试图准确了解它如何根据输入值的大小选择正确的函数。

特殊的调味料似乎是这个__tg_promote宏,但我挖得越深,这个谜题就越深。有没有人对__tg_promote实际做什么有一个简短的答案?

在 clang 的tgmath.h实现中,__tg_promote实际上似乎是一个函数,而不是一个宏。定义可以在这里找到。

typedef void _Argument_type_is_not_arithmetic;
static _Argument_type_is_not_arithmetic __tg_promote(...)
  __attribute__((__unavailable__,__overloadable__));
static double               _TG_ATTRSp __tg_promote(int);
static double               _TG_ATTRSp __tg_promote(unsigned int);
static double               _TG_ATTRSp __tg_promote(long);
static double               _TG_ATTRSp __tg_promote(unsigned long);
static double               _TG_ATTRSp __tg_promote(long long);
static double               _TG_ATTRSp __tg_promote(unsigned long long);
static float                _TG_ATTRSp __tg_promote(float);
static double               _TG_ATTRSp __tg_promote(double);
static long double          _TG_ATTRSp __tg_promote(long double);
static float _Complex       _TG_ATTRSp __tg_promote(float _Complex);
static double _Complex      _TG_ATTRSp __tg_promote(double _Complex);
static long double _Complex _TG_ATTRSp __tg_promote(long double _Complex);

这是一个具有多个重载的函数(在 C 中通常不允许(并且没有定义,这很好,因为它从未真正被调用过! __tg_promote仅用于确定数值类型应提升为的类型。(整型类型要double;浮点类型要自身。当您查看接下来的几个宏时,这一点很清楚:

#define __tg_promote1(__x)           (__typeof__(__tg_promote(__x)))
#define __tg_promote2(__x, __y)      (__typeof__(__tg_promote(__x) + 
                                                 __tg_promote(__y)))
#define __tg_promote3(__x, __y, __z) (__typeof__(__tg_promote(__x) + 
                                                 __tg_promote(__y) + 
                                                 __tg_promote(__z)))

未调用 __tg_promote 函数,因为它发生在特定于编译器的__typeof__宏中。__tg_promote1宏只是在括号内扩展到其参数的提升类型__tg_promote2 扩展为类型(再次用括号括起来(,如果添加其参数的提升类型的两个值,将产生该类型。因此,例如,__tg_promote2(0.0f, 0)将是(double),因为添加floatdouble(提升int的结果(会给出double__tg_promote3是相似的。

标头的其余部分由委托给相应普通 C 函数的函数的重载定义组成:

// atan2
static float
    _TG_ATTRS
    __tg_atan2(float __x, float __y) {return atan2f(__x, __y);}
static double
    _TG_ATTRS
    __tg_atan2(double __x, double __y) {return atan2(__x, __y);}
static long double
    _TG_ATTRS
    __tg_atan2(long double __x, long double __y) {return atan2l(__x, __y);}

为了能够调用,比如说,atan2(1.0f, 1)我们需要能够委派给__tg_atan2(double, double) .这就是__tg_promote2确定当我们有一个float参数和一个int参数时,两者都应该转换为double

#define atan2(__x, __y) __tg_atan2(__tg_promote2((__x), (__y))(__x), 
                                   __tg_promote2((__x), (__y))(__y))

所以在这种情况下,__tg_promote2((__x), (__y))扩展到(double),我们得到__tg_atan2((double)(__x), (double)(__y)),这正是我们想要的。