現代 C (C11/C17/C23)

型別泛型數學(<tgmath.h>)

/ TEE-jee-math /

在 C 裡,sqrt() 處理 double、sqrtf() 處理 float、sqrtl() 處理 long double。每次都要寫對後綴既煩瑣又容易出錯,尤其當你後來改了某個變數的型別。標頭檔 <tgmath.h> 給你「一個」名字 sqrt(x),依 x 的型別自動導向正確大小的函式。

在底層,<tgmath.h> 定義的是巨集(不是函式),名字和一般數學函式相同。每個巨集對其引數做 _Generic 風格的型別分派:若 x 是 float 就展開成 sqrtf、是 double 就展開成 sqrt、是 long double 就展開成 sqrtl,並且也處理來自 <complex.h> 的複數版本(csqrt 等)。因此引入 <tgmath.h> 會用這些分派巨集遮蔽 <math.h> 與 <complex.h> 的一般名字。效果是數學程式碼變得型別可移植:把 x 從 double 改成 float,每個呼叫都會跟著走。

它對數值與科學程式碼很重要,那時你想把演算法只寫一次卻在多種精度下實例化。誠實的提醒:因為它們是巨集,你無法在 <tgmath.h> 下取得 sqrt 的位址、引數可能以令你意外的方式被文字替換,而錯誤訊息也會更難懂。此外整數引數會被提升為 double(所以 sqrt(2) 呼叫的是 double 版本),這通常正是你要的,但值得知道。

#include <tgmath.h> float f = 2.0f; double d = 2.0; float rf = sqrt(f); // 展開成 sqrtf(f) double rd = sqrt(d); // 展開成 sqrt(d)

同一個寫法 sqrt,依引數型別挑選 sqrtf 或 sqrt——這個路由正是 _Generic 在運作。

它們是巨集而非函式:在 <tgmath.h> 下 &sqrt 不會指向某個函式,且引數可能以意外方式被求值或替換,所以避免在 tgmath 引數中放入副作用。

又称
tgmathtype-generic math header型別泛型數學標頭檔