2010-12-02 68 views
7

這是可以做到的某些類型的類型泛型函數作爲宏在Ç,例如之類的東西:使用宏進行類型泛型編程:使用技巧來確定類型?

#define SQRT(x) (sizeof(x) == sizeof(float) ? sqrtf((x)) : \ 
       sizeof(x) == sizeof(double) ? sqrt((x)) : \ 
       sqrtl((x))) 

此作品(大部分)作爲只要x是浮點型的預期。

但是,如果我想要一個類型通用宏,可以採取一個整數類型或指針類型,它可能具有相同的大小。有一種聰明的方法來測試宏參數是一個整數還是一個指針?整數與浮點類型有什麼關係?

回答

3

編號宏不知道是什麼類型。他們執行#define的文字複製和粘貼。類型安全在這裏根本不存在。

從任何有意義的意義上說C不是一種強類型語言。如果你想要一些類型安全的小東西,可以使用C++,在那裏你可以用模板和函數重載來完成一些工作。

+0

宏並不是天生就知道的,但有時候會有技巧。例如,`((0 *(x)-1)<0)`可以確定是否簽署了x(假設x的轉換等級爲int或更高)。 – 2010-12-02 04:06:57

0

這是可能有某種類型檢查系統,但它確實是在C的雜牌

glib做到這一點;你可以看看他們是怎麼做的,或者可以自己使用它(無論如何它都是一個漂亮的C庫)。

3

你的結果是不是真的泛型,因爲結果總是long double不管是什麼類型的參數傳遞的 - 的?:結果類型時,第二個和第三個操作數是算術類型是類型會將通常的算術轉換應用於這些操作數。爲了讓這樣,你可以使用GCC的typeof擴展:

#define SQRT(x) (__typeof__ (x))(sizeof(x) == sizeof(float) ? sqrtf((x)) : \ 
       sizeof(x) == sizeof(double) ? sqrt((x)) : \ 
       sqrtl((x))) 

整數與浮點還可以使用typeof完成:

(__typeof__ (X))1.1 == 1 

我不能想辦法做整型與指針。雖然在this page上描述的技術非常有趣。

3

表達式是否其中鑄造由指針uintptr_t被很好地定義的整數表達式或char*表達,至少在架構可在檢測:

#define INT_OR_CHARP(X) (((uintptr_t)((X)+1) - (uintptr_t)(X)) == 1) 

這將檢測是否X是一個指向鍵入Tsizeof(T) > 1。這不適用於void*和其他角落案件。並且因爲X被評估了兩次,所以您必須注意副作用。

爲了避免整數溢出問題,如果X是e.g類型的signed int您可以用

(1 ? (X) : (uintmax_t)0) 

這保證如果X是一個整數表達式,這將是uintmax_t類型的替代(X)。然後+1可能會環繞,但結果總是很好定義,並且兩個部分之間的差異始終是1。如果X是指針表達式,那麼這是因爲任何值爲0的恆定整數表達式也是空指針常量

在總這給出

#define INT_OR_CHARP(X) (((uintptr_t)((1 ? (X) : (uintmax_t)0)+1) - (uintptr_t)(1 ? (X) : (uintmax_t)0)) == 1) 
+0

我不明白'(1?(X):(uintmax_t)0)`是有用的。這是``:`操作符強制類型的某種伎倆嗎?無符號類型也不會溢出。 – 2010-12-02 13:55:55

1

C11 standard加入用於此目的的_Generic關鍵字。

它的工作方式類似於表達式類型的switch語句。

您的例子可以使用此關鍵字這樣寫:

#define SQRT(X) _Generic((X), 
    float: sqrtf, \ 
    double: sqrt, \ 
    default: sqrtl \ 
)(X) 

GCC提供自version 4.9此關鍵字的支持。