新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「編程珠璣」,作者守望先生。轉(zhuǎn)載本文請(qǐng)聯(lián)系編程珠璣公眾號(hào)。

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括湖南網(wǎng)站建設(shè)、湖南網(wǎng)站制作、湖南網(wǎng)頁(yè)制作以及湖南網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,湖南網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到湖南省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
在回答標(biāo)題問(wèn)題之前,先了解下什么是泛型編程。
泛型編程(generic programming)是程序設(shè)計(jì)語(yǔ)言的一種風(fēng)格或范式。泛型允許程序員在強(qiáng)類型程序設(shè)計(jì)語(yǔ)言中編寫(xiě)代碼時(shí)使用一些以后才指定的類型,在實(shí)例化時(shí)作為參數(shù)指明這些類型。C++支持泛型編程,也就是模板,比如:
- // 來(lái)源:公眾號(hào)【 編程珠璣】
- // 作者:守望先生
- #include
- template
- T add(T a,T b){
- T ret = a + b;
- std::cout<< a << " + " << b <<" = " << ret << std::endl;
- return ret;
- }
- int main(){
- add(1,2); // 整數(shù)相加
- add(1.2,2.3); // 浮點(diǎn)數(shù)相加
- return 0;
- }
運(yùn)行結(jié)果:
- 1 + 2 = 3
- 1.2 + 2.3 = 3.5
從上面的結(jié)果可以看到,對(duì)于調(diào)用add函數(shù),如果傳入的是整型,則按照整型加法計(jì)算,如果是浮點(diǎn)數(shù),則按照浮點(diǎn)數(shù)進(jìn)行加法計(jì)算。也就是說(shuō),add函數(shù)沒(méi)有針對(duì)特定類型(泛型)。
你同樣可以使用重載實(shí)現(xiàn)上面的功能,但是存在大量重復(fù)代碼。
C語(yǔ)言支持泛型編程嗎?
很遺憾,C語(yǔ)言本身不支持真正意義上的泛型編程,但是卻在一定程度上可以“實(shí)現(xiàn)泛型編程”。
_Generic關(guān)鍵字
_Generic是C11的關(guān)鍵字,通過(guò)該關(guān)鍵字可以有一個(gè)泛型表達(dá)式:
- _Generic((value). int:"int", float:"float",char*:"char*",default:"other type")
什么意思呢?如果value是int類型,那么表達(dá)式的值就是“int”,其他的以此類推??雌饋?lái)是不是和switch語(yǔ)句有點(diǎn)類似呢?
根據(jù)這個(gè)示例,我們來(lái)實(shí)現(xiàn)一個(gè)功能,打印變量或常量到底是什么類型:
- // 來(lái)源:公眾號(hào)【編程珠璣】
- // 作者:守望先生
- #include
- #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;
- }
這里為了方便使用,我們通過(guò)define關(guān)鍵字,將泛型表達(dá)式簡(jiǎn)化。
運(yùn)行結(jié)果:
- 1 + 2 type: int
- 1/3 type: int
- 2/3 type: float
- xxx type: char*
可以看到通過(guò)TYPE就可以獲得表達(dá)式的結(jié)果類型,這對(duì)初學(xué)者來(lái)說(shuō),可真是福音了。
泛型算法
既然C語(yǔ)言有_Generic關(guān)鍵字了,那么我們嘗試實(shí)現(xiàn)開(kāi)頭C++示例代碼中的加法??催^(guò)上面的例子后,相信你已經(jīng)會(huì)了:
- // 來(lái)源:公眾號(hào)【編程珠璣】
- // 作者:守望先生
- #include
- // 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;
- }
觀察上面的代碼,我們注意到:
- 在這里,我們需要定義兩種類型的加法(實(shí)際上,通過(guò)C++的模板,由編譯器幫我們完成了這件事),由于C語(yǔ)言中并不支持重載,因此兩個(gè)加法的函數(shù)名不一樣。
- 由于涉及參數(shù)有兩個(gè),在做類型判斷時(shí),如果兩個(gè)參數(shù)不一致,可能仍然存在編譯問(wèn)題
- 調(diào)用者無(wú)需區(qū)分被加對(duì)象是什么類型,都可以統(tǒng)一使用ADD
C99的tgmath.h
前面說(shuō)到,_Generic關(guān)鍵字在C11中才有,那么C99怎么辦呢?實(shí)際上,tgmath.h中提供了一些泛型類型宏,如果math.h的函數(shù)中定義了float,double和long double版本,tgmath就會(huì)提供一個(gè)泛型類型宏。效果和前面的例子一樣,舉個(gè)例子:
- // 來(lái)源:公眾號(hào)【編程珠璣】
- // 作者:守望先生
- #include
- #include
- int main(void)
- {
- float f = 4.0f;
- long double d = 1.44;
- printf("%f\n",sqrt(f)); // 實(shí)際上調(diào)用了sqrtf
- printf("%Lf\n",sqrt(d)); // 實(shí)際上調(diào)用了sqrtl
- return 0;
- }
編譯運(yùn)行結(jié)果:
- 2.000000
- 1.200000
但是不得不說(shuō),tgmath中提供的泛型宏也是有限的。
void *指針
眾所周知,C語(yǔ)言中void *指針是一種無(wú)類型指針,從這點(diǎn)看,也可以算是泛型指針了。而它的使用在C語(yǔ)言中是非常常見(jiàn)的,舉例來(lái)說(shuō),在《高級(jí)指針話題-函數(shù)指針》中,我們介紹了快速排序接口的使用,它的函數(shù)聲明是這樣的:
- #include
- void qsort(void *base, size_t nmemb, size_t size,
- int (*compar)(const void *, const void *));
庫(kù)函數(shù)qsort實(shí)際上就是泛型排序算法了,它可以針對(duì)任何類型的數(shù)據(jù)進(jìn)行排序。當(dāng)然有一個(gè)前提,就是你需要按照它的協(xié)議,實(shí)現(xiàn)一個(gè)compar函數(shù),用于比較大小。
像這樣類似的例子,C語(yǔ)言中還有很多,不過(guò)相比于其他語(yǔ)言,如C++中的模板,這種所謂的泛型,確實(shí)有些小巫見(jiàn)大巫了。
總結(jié)
C語(yǔ)言語(yǔ)法上本身基本不支持泛型編程,但是借助_Generic關(guān)鍵字和一些手段,可以實(shí)現(xiàn)泛型編程。
作者:守望,linux應(yīng)用開(kāi)發(fā)者,目前在公眾號(hào)【編程珠璣】?分享Linux/C/C++/數(shù)據(jù)結(jié)構(gòu)與算法/工具等原創(chuàng)技術(shù)文章和學(xué)習(xí)資源。
文章標(biāo)題:原來(lái)C語(yǔ)言還可以這樣實(shí)現(xiàn)“泛型編程”!
文章轉(zhuǎn)載:http://m.5511xx.com/article/cdocsgo.html


咨詢
建站咨詢
