您好,登錄后才能下訂單哦!
這篇文章給大家介紹C語言中怎么實現泛型編程,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
泛型編程(generic programming)是程序設計語言的一種風格或范式。泛型允許程序員在強類型程序設計語言中編寫代碼時使用一些以后才指定的類型,在實例化時作為參數指明這些類型。C++支持泛型編程,也就是模板,比如:
// 來源:公眾號【 編程珠璣】 // 作者:守望先生 #include <iostream> template <class T> T add(T a,T b){ T ret = a + b; std::cout<< a << " + " << b <<" = " << ret << std::endl; return ret; } int main(){ add(1,2); // 整數相加 add(1.2,2.3); // 浮點數相加 return 0; }
運行結果:
1 + 2 = 3 1.2 + 2.3 = 3.5
從上面的結果可以看到,對于調用add函數,如果傳入的是整型,則按照整型加法計算,如果是浮點數,則按照浮點數進行加法計算。也就是說,add函數沒有針對特定類型(泛型)。
你同樣可以使用重載實現上面的功能,但是存在大量重復代碼。
C語言支持泛型編程嗎?
很遺憾,C語言本身不支持真正意義上的泛型編程,但是卻在一定程度上可以“實現泛型編程”。
_Generic關鍵字
_Generic是C11的關鍵字,通過該關鍵字可以有一個泛型表達式:
_Generic((value). int:"int", float:"float",char*:"char*",default:"other type")
什么意思呢?如果value是int類型,那么表達式的值就是“int”,其他的以此類推。看起來是不是和switch語句有點類似呢?
根據這個示例,我們來實現一個功能,打印變量或常量到底是什么類型:
// 來源:公眾號【編程珠璣】 // 作者:守望先生 #include <stdio.h> #define TYPE(v) _Generic((v), \ int:"int", \ char:"char", \ float:"float", \ double:"double", \ char*:"char*", \ default:"other type") int main(void) { printf("1 + 2 type: %s\n",TYPE(1 + 2)); printf("1/3 type: %s\n",TYPE(1/3)); printf("2/3 type: %s\n",TYPE((float)2/3)); printf("xxx type: %s\n",TYPE("xxx")); return 0; }
這里為了方便使用,我們通過define關鍵字,將泛型表達式簡化。
運行結果:
1 + 2 type: int 1/3 type: int 2/3 type: float xxx type: char*
可以看到通過TYPE就可以獲得表達式的結果類型,這對初學者來說,可真是福音了。
泛型算法
既然C語言有_Generic關鍵字了,那么我們嘗試實現開頭C++示例代碼中的加法。看過上面的例子后,相信你已經會了:
// 來源:公眾號【編程珠璣】 // 作者:守望先生 #include <stdio.h> // int類型加法 int addI(int a, int b) { printf("%d + %d = %d\n",a,b, a + b ); return (a + b); } // double類型加法 double addF(double a, double b) { printf("%f + %f = %f\n",a,b, a + b ); return (a + b); } void unsupport(int a,int b) { printf("unsupport type\n"); } #define ADD(a,b) _Generic((a), \ int:addI(a,b),\ double:addF(a,b), \ default:unsupport(a,b)) int main(void) { ADD(1 , 2); ADD(1.1,2.2); return 0; }
觀察上面的代碼,我們注意到:
在這里,我們需要定義兩種類型的加法(實際上,通過C++的模板,由編譯器幫我們完成了這件事),由于C語言中并不支持重載,因此兩個加法的函數名不一樣。
由于涉及參數有兩個,在做類型判斷時,如果兩個參數不一致,可能仍然存在編譯問題
調用者無需區分被加對象是什么類型,都可以統一使用ADD
C99的tgmath.h
前面說到,_Generic關鍵字在C11中才有,那么C99怎么辦呢?實際上,tgmath.h中提供了一些泛型類型宏,如果math.h的函數中定義了float,double和long double版本,tgmath就會提供一個泛型類型宏。效果和前面的例子一樣,舉個例子:
// 來源:公眾號【編程珠璣】 // 作者:守望先生 #include <stdio.h> #include <tgmath.h> int main(void) { float f = 4.0f; long double d = 1.44; printf("%f\n",sqrt(f)); // 實際上調用了sqrtf printf("%Lf\n",sqrt(d)); // 實際上調用了sqrtl return 0; }
編譯運行結果:
2.000000 1.200000
但是不得不說,tgmath中提供的泛型宏也是有限的。
void *指針
眾所周知,C語言中void *指針是一種無類型指針,從這點看,也可以算是泛型指針了。而它的使用在C語言中是非常常見的,舉例來說,在《高級指針話題-函數指針》中,我們介紹了快速排序接口的使用,它的函數聲明是這樣的:
#include <stdlib.h> void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
庫函數qsort實際上就是泛型排序算法了,它可以針對任何類型的數據進行排序。當然有一個前提,就是你需要按照它的協議,實現一個compar函數,用于比較大小。
關于C語言中怎么實現泛型編程就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。