C1X系列:type-generic macros

C1X系列:type-generic macros

 

承蒙轉載,請保持本文的完整性,請匆用於商業用途。


type-generic macros在新的C1X草案又稱爲Generic selection,根據它的提案和最新C1X草案,可將type-generic macros翻譯成泛型宏或者通用類型宏。 type-generic macros是一種編譯期技術,它允許開發人員根據宏的某個參數的類型來確定生成的內容。這與C++中的函數重載有點類似,但又有不同。

type-generic macros並不是 C1X提出的概念,早在C99時就有了,只不過當時沒有對它進行標準化。 C99中引用了頭文件<tgmath.h>,給開發人員提供大量初等數學數函接口。

在C99中,程序員可以以不同的類型來調用 sin函數, 比如:

sin(1), 實際上調用sin(1.0)

sin(1.0F), 實際上調用sinf(1.0F)

sin(1.0L),實際上調用sinl(1.0L)

實際上,sin這個接口是一個宏,它會用戶傳遞的實際類型來決定最終調用的函數。 sin就是一個type-generic macro。

1. type-generic macros的技術現狀

爲了實現C99中tgmath.h中的接口,各個編譯器八仙過海,各顯神通。

 

Edison Design Group(EDG)爲實現tgmath.h提出了一種編譯魔法,讓開發人員(庫的開發者)使用__generic可輕鬆實現tgmath.h的接口。如上述的sin接口可定義如下:

#define sin(x) __generic(x,,, sin, sinf, sinl, csin, csinf, csinl)(x)

__generic就是EDG的把戲,它並不生成生代碼,只在編譯期,根據x的類型float, double, long double, float complex, double complex或long double complex來選擇後面對應的6個函數。

當然EDG的__generic用來實現C1X的type-generic macros是不行的,它只能識別浮點數和複數一共6種類型,並且__generic後的六種函數必須按這種順序來排列, 但對C99標準中的generic function,這種技術已足夠了。

 

gnu GCC算得上是一個體貼入微的編譯器,它在不違背標準和C語義的情況下,提供很多編譯時的內置小工具,讓你編寫功能強太,可以控制更底層的代碼。當然,這些feature只能在gcc上使用。

C99中的sin在gcc可以蟬聯 __builtin_choose_expr,__builtin_types_compatible_p和typeof來實現。

  1. #define sin(x)                                                     /  
  2.         __builtin_choose_expr (                                    /  
  3.           __builtin_types_compatible_p (typeof (x), long double),  /  
  4.           sinl(x),                                                 /  
  5.            __builtin_choose_expr (                                 /  
  6.             __builtin_types_compatible_p (typeof (x), double),     /  
  7.             sinf(x),                                               /  
  8.   
  9.             sin(x)))  
__builtin_types_compatible_p (typeof (x), long double) 在編譯期判斷x的基礎類型是否爲long double(即除去const, volatile
等修飾符後的類型), 而__builtin_choose_expr 是編譯期的三元組運算符,如果條件爲true,則運算第一個表達式,否則運算第二個




表達式。gcc編譯器的tgmath.h實現,並沒有使用上述的__builtin_技術,而是使用一些sizeof, typeof和其它__builtin_,但可讀性非常差。

C1X之type-generic macros

目前type-generic macros有兩個提案,分別是N1340 Extensible Generic Math Functions 和N1404 General support for type-generic macros . N1340從C99的tgmath實現談起,提出將EDG的實現方案進行標準化,以解開發人員編寫可移植的泛型宏之苦。N1404在N1340的基礎上,對type-generic macros的語法形式方面進行改進,現已成形於最新的C1X草案中。

C1X中引入了新關鍵字_Generic來實現type-generic macros, 這就一個語法糖魔術,它根據第一個參數的類型,和後面的類型-表達式關聯來實現編譯期的替換。它的語法格式規定如下:

  1. generic-selection:  
  2.     _Generic ( assignment-expression , generic-association-list )  
  3. generic-association-list:  
  4.     generic-association  
  5.     generic-association-list , generic-association  
  6. generic-association:  
  7.     type-name : assignment-expression  
  8.     default : assignment-expression  

利用_Generic,C99的sin 可定義如下:

 

  1. #define sin(x)                      /  
  2.         _Generic(x,                 /  
  3.                 long double: sinl,  /  
  4.                 double: sinf,       /  
  5.                 defualt: sin        /  
  6.                 )(x)  

 

_Generic對第一個參數進行類型判斷,然後根據從第二參數開始的類型-表達式關聯表來進行編譯期替換(或生成)。如果x爲long double類型,那麼_Generic(x, …)的結果爲sinl,如果x爲double類型,那麼_Generic(x,…)的結果爲sinf,否則結果爲sin。可見_Generic實現就是一個generic selection。

有了_Generic,原本只有編譯器才能玩的語法把戲,我們一樣可以玩。例如編一個sum的數學接口,如下:

 

  1. int sumi(int *arr, int cnt)  
  2. {  
  3.     int sum = 0;  
  4.     int i;  
  5.       
  6.     for(i = 0; i < cnt; ++i) {  
  7.          sum += arr[i];  
  8.     }  
  9.     return sum;  
  10. }  
  11. double sumf(double *arr, int cnt)  
  12. {  
  13.     double sum = 0.0;  
  14.     int i;  
  15.       
  16.     for(i = 0; i < cnt; ++i) {  
  17.             sum += arr[i]  
  18.     }  
  19.     return sum;  
  20. }  
  21. #define sum(_arr, _cnt) /  
  22.        _Generic(_arr[0],    /  
  23.                 int: sumi,  /  
  24.                 defualt: sumf  /  
  25.                )(_arr, _cnt)  

 

  如果_Generic中的參數可以支持更復雜的表達式,那就可以用來實現C++中的部分元編程,可惜它的參數表達式有限制。 不管怎麼說_Generice是用來實現泛型宏的,而不是給開發人員任何變換的法戲,因此它的價值在於方便編寫可移植的泛型宏。


from: http://blog.csdn.net/linyt/article/details/5966485

發佈了11 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章