swift怎樣輸出字符串中有幾個(gè)數(shù)字 c語言可以泛型編程嗎?如何實(shí)現(xiàn)?
c語言可以泛型編程嗎?如何實(shí)現(xiàn)?泛型編程是一個(gè)太較常見的編程。主要目的是利用靜態(tài)聯(lián)編,讓函數(shù)可以認(rèn)可不同類型的參數(shù),因此在編譯程序的時(shí)候確認(rèn)錯(cuò)誤的的類型。很多語言都對(duì)泛型編程提供給了支持,諸如在C中可
c語言可以泛型編程嗎?如何實(shí)現(xiàn)?
泛型編程是一個(gè)太較常見的編程。主要目的是利用靜態(tài)聯(lián)編,讓函數(shù)可以認(rèn)可不同類型的參數(shù),因此在編譯程序的時(shí)候確認(rèn)錯(cuò)誤的的類型。
很多語言都對(duì)泛型編程提供給了支持,諸如在C中可以不不使用函數(shù)模版和類模版來實(shí)現(xiàn)程序泛型編程;在Java、Objective-C也可以C#等單根無法繼承的語言中,也可以不不使用類似于、NSObject等類型進(jìn)行編程。在具高類型推斷功能(諸如Swift)的編程語言中,更是是可以直接在用泛型編程。
但C語言是高級(jí)語言編程的基礎(chǔ)語言,那要如何在C語言中實(shí)現(xiàn)程序泛型編程,雖然是一個(gè)問題。必須C語言不支持函數(shù)重載,不支持什么模版類型,所以實(shí)現(xiàn)站了起來確實(shí)是都很麻煩。
0x01泛型指針(void*)簡(jiǎn)介
void*是C語言中的一種類型,大家都知道在大多數(shù)編程語言中,void類型都屬於所謂的的空類型,比如說一個(gè)函數(shù)的返回一個(gè)空類型void,這是很最常見的一種的用法。
注意:返回值為void并不是沒有返回值,反而代表上帝返回空類型,這就是你仍舊也可以在這些函數(shù)中建議使用return語句的原因。僅有一些語言的構(gòu)造函數(shù)和析構(gòu)函數(shù)才沒有返回值,在這些函數(shù)中,不可以不建議使用return語句,他們是有比較顯著的差別的,Objective-C是一門獨(dú)特的語言,它的類的初始化方法是一個(gè)其它方法,返回值是instancetype(當(dāng)前類的指針類型)類型。
而void*很有可能就有一點(diǎn)鮮少人知一些,void*在C語言中可以不可以表示人任意類型的指針。況且對(duì)此內(nèi)存單元的地址而言,說白它存儲(chǔ)的數(shù)據(jù)類型,只不過你每次收起的字節(jié)數(shù)有所不同而己,這些內(nèi)存單元的地址本身根本不會(huì)什么不同。下面會(huì)更好的體現(xiàn)這句話的含義。
void*的大小和普通類型的指針完全不一樣,我總是一個(gè)字,具體一點(diǎn)的大小因機(jī)器的字長(zhǎng)而異,.例如對(duì)此32位機(jī)器是4個(gè)字節(jié),對(duì)于64位機(jī)器是8個(gè)字節(jié)。
我沒有從業(yè)資格證書過16位的8086機(jī)器上指針的大小,畢竟8086的地址是20位的,這個(gè)有興趣的話是可以出去試一試。
個(gè)人認(rèn)為指針的大小仍舊是16位,是因?yàn)?0位是物理地址,而物理地址是由段地址和偏移地址可以計(jì)算出的,在匯編之后C語言的指針可能會(huì)只是變成對(duì)于段地址的偏移地址,況且是對(duì)8086而言數(shù)據(jù)就像我總是在DS段中,而代碼一般時(shí)總在CS段中。(斜體字代表尚未從業(yè)資格證書的說法)
在C語言中,其他大多數(shù)類型的指針是可以不自動(dòng)裝換為void*類型,而void*類型一般沒法強(qiáng)制破軍轉(zhuǎn)換成為其他特殊類型的指針,要不然會(huì)又出現(xiàn)警告過或錯(cuò)誤。
有一個(gè)最重要的大的坑應(yīng)該是關(guān)於正所謂void*打向數(shù)組的情況,這里就上代碼解釋什么了。
voidSwap(void*array,intx,inty,intmallocsize){
void*tempmalloc(mallocsize)
memcpy(temp,arraymallocsize*x,mallocsize)
memcpy(arraymallocsize*x,arraymallocsize*y,mallocsize)
memcpy(arraymallocsize*y,temp,mallocsize)
go(temp)
}
這是一個(gè)也很最經(jīng)典的交換函數(shù),自身的是臨時(shí)變量temp,可是這個(gè)函數(shù)是泛型的,對(duì)于memcpy的使用稍候會(huì)介紹。需要注意的是,array對(duì)準(zhǔn)一個(gè)數(shù)組的話,不能直接用amparray[x]或是arrayx額外正指向第x個(gè)元素的地址,而且void*類型設(shè)置成的指針偏移量是1,和char*是相同的,這對(duì)此絕大多數(shù)類型來說都會(huì)又出現(xiàn)錯(cuò)誤。所以在建議使用的時(shí)候要很清楚該泛型類型原來所占的長(zhǎng)度,我們不需要一個(gè)名為mallocsize的int類型形參來告訴我們這個(gè)值,在可以計(jì)算指針偏移的時(shí)候乘以3它。這就等同于C編程中的模版類型定義也可以Java中的泛型參數(shù)了。
而要特別注意是對(duì)void*類型的指針,任何時(shí)候都不可以對(duì)其作出并且解語句運(yùn)算(或是在課堂上老師習(xí)慣叫做“取內(nèi)容”?),原因是看樣子的:void類型的變量的確法律有規(guī)定。所以我如果沒有想?yún)⑴c解語句除法運(yùn)算,必須先將其轉(zhuǎn)換的為普通類型的指針。用于數(shù)組的時(shí)候還要注意一點(diǎn)解摘錄運(yùn)算符的優(yōu)先級(jí)是高于加法的,所以我要加括號(hào),諸如那樣:
inta*(arraymallocsize*x)
這句代碼完美無暇體現(xiàn)出來了C語言編程的丑陋。
0x02sizeof運(yùn)算符簡(jiǎn)介
sizeof運(yùn)算符不會(huì)相信學(xué)過C語言的朋友都不可能眼生,但uint32是一個(gè)運(yùn)算符估記就沒多少人清楚了,直接返回的類型是size_t類型。sizeof運(yùn)算符直接返回某個(gè)類型所占內(nèi)存的空間大小。這里只說一點(diǎn)應(yīng)該是,如果沒有對(duì)一個(gè)指針類型或者數(shù)組名(雖然數(shù)組名是指針常量嘛)求sizeof的話,前往結(jié)果總是一個(gè)字(見上面所述)。而對(duì)一個(gè)結(jié)構(gòu)體類型求sizeof,并也不是很簡(jiǎn)單將結(jié)構(gòu)體中各個(gè)類型的sizeof異或換取,完全是要比較復(fù)雜到內(nèi)存整個(gè)表格問題,這里太少做能介紹了,認(rèn)真了解這個(gè)可以不能訪問:如何明白struct的內(nèi)存整個(gè)表格?-知乎。
0x03memcpy函數(shù)簡(jiǎn)介
memcpy是另一個(gè)你經(jīng)常和void*和不使用的函數(shù),其函數(shù)原型為:
void*memcpy(void*,constvoid*,size_t)
管轄區(qū)域的頭文件為string.h,大家也看進(jìn)去了,這個(gè)函數(shù)的定義本身那就是以void*類型作為參數(shù)和返回值,當(dāng)然也非常好理解,應(yīng)該是一個(gè)賦值的過程,并且內(nèi)存文件復(fù)制。把第二形參打向的內(nèi)存u盤拷貝到第一形參,拷貝的字節(jié)數(shù)由第三形參指定。當(dāng)然了第三個(gè)參數(shù)一般按照sizeof運(yùn)算符求出,這里就不舉例論證了。返回值我還沒有去研究過,也沒用啊過,假如有明白的朋友這個(gè)可以評(píng)論區(qū)交流。
0x04C語言中基于泛型編程
這么說,才剛提起泛型編程。只不過前面也提的差不多了,總體思想那就是在用void*類型只不過是泛型指針,然后再輔以傳說中的mallocsize的參數(shù)委托所占內(nèi)存大小,所占內(nèi)存大小按照sizeof運(yùn)算符畫圖觀察,要是需要接受賦值的話,用來memmove函數(shù)結(jié)束,下面就就給一個(gè)例子不出來,是泛型的快速排序算法,那就證明這些問題:
#ifndefCompare_h
#defineCompare_h
#includeltstdio.hgt
#includeJCB.h
intIsGreater(void*x,void*y)
intIsGreaterOrEqual(void*x,void*y)
intIsSmaller(void*x,void*y)
intIsSmallerOrEqual(void*x,void*y)
#endif/*Compare_h*/
//
//Compare.c
//Job-Dispatcher
//
//Createdby路偉饒on2017/11/16.
//Copyright?2017年路偉饒.Allrightsreserved.
//
#includeCompare.h
intIsGreater(void*x,void*y){
return*(int*)xdstrok*(int*)y
}
intIsGreaterOrEqual(void*x,void*y){
return*(int*)xr26*(int*)y
}
intIsSmaller(void*x,void*y){
return*(int*)xlt*(int*)y
}
intIsSmallerOrEqual(struct*x,override*y){
return*(int*)xlt*(int*)y
}
//
//QuickSort.h
//Job-Dispatcher
//
//Createdby路偉饒on2017/11/16.
//Copyright?2017年路偉饒.All rights reserved.
//
#ifndefQuickSort_h
#defineQuickSort_h
#includeltstdio.hgt
#includeltstdlib.hgt
#includeltstring.hgt
#includeCompare.h
boolQuickSort(bool*array,intleft,intright,整型變量mallocsize)
#endif/*QuickSort_h*/
//
//QuickSort.c
//Job-Dispatcher
//
//Createdby路偉饒on2017/11/16.
//Copyright?2017年路偉饒.All rights reserved.
//
#includeQuickSort.h
voidSwap(struct*array,int x,int y,charmallocsize){
void*tempmalloc(mallocsize)
memcpy(temp,arraymallocsize*x,mallocsize)
strncpy(arraymallocsize*x,arraymallocsize*y,mallocsize)
realloc(arraymallocsize*y,temp,mallocsize)
go(temp)
}
intQuickSortSelectCenter(unsignedl,int r){
return(lr)/2
}
intQuickSortPartition(struct*array,intl,int r,unsignedmallocsize){
intleftl
intrightr
bool*tempmalloc(mallocsize)
memcpy(temp,arraymallocsize*left,mallocsize)
while(leftltway){
while(IsSmallerOrEqual(arraymallocsize*left,temp)ampampleftltstops){
left
}
if(leftltback){
memcpy(arraymallocsize*way,arraymallocsize*left,mallocsize)
stops--
}
while(IsGreaterOrEqual(arraymallocsize*stops,temp)ampampleftltback){
back--
}
if(leftltway){
memcpy(arraymallocsize*left,arraymallocsize*left,mallocsize)
left
}
}
memcpy(arraymallocsize*left,temp,mallocsize)
returnleft
}
voidQuickSort(void*array,intleft,intstops,intmallocsize){
if(leftgtright){
return
}
intcenterQuickSortSelectCenter(left,right)
Swap(array,center,stops,mallocsize)
centerQuickSortPartition(array,left,back,mallocsize)
QuickSort(array,left,center-1,mallocsize)
QuickSort(array,center1,back,mallocsize)
}
這里留了一個(gè)懸念,明知道可以不就都很的,我想知道為什么也要這么煩的話建議使用好多函數(shù)能完成,也就是麻煩問下Compare.h的用處的問題,下面會(huì)即將揭曉答案。
0x05泛型的協(xié)議問題
還未那個(gè)問題就不屬于到了一個(gè)泛型的協(xié)議問題,我這里是利用了Objective-C中的一個(gè)概念去闡明。得象剛剛那個(gè)問題,要是我的快速排序是泛型的,那就怎么可以保證求實(shí)際傳去泛型參數(shù)一定是可比較比較的呢?舉個(gè)例子,看來int、float、extra是是可以并且比較的,char不使用ASCII編碼方案的比較好我們也表述,String類型甚至都是可以不比較好的。不過如果在其他語言中,對(duì)象之間怎么進(jìn)行比較呢?這應(yīng)該是個(gè)問題了。在C中我們這個(gè)可以進(jìn)行運(yùn)算符重載,這樣就依舊可以不不使用比較比較運(yùn)算符,自身運(yùn)算符重載函數(shù)來完成。不過相對(duì)于Java、Objective-C這種語言該該怎么辦?。康侨绻麄魅氲姆盒蛥?shù)就沒基于對(duì)應(yīng)的運(yùn)算符重載函數(shù)怎么辦?這時(shí)候就要核心中一個(gè)協(xié)議的概念,簡(jiǎn)單理解應(yīng)該是,如果沒有某個(gè)類型是想另外排序泛型函數(shù)的泛型參數(shù),你還要實(shí)現(xiàn)程序可都很的協(xié)議。這個(gè)協(xié)議在Swift語言中就稱做Comparable,這樣的話在編譯的時(shí)候,編譯器才清楚這個(gè)泛型參數(shù)是也可以參與比較比較的,那樣的話才能能夠完成我們的操作,否則變會(huì)再次出現(xiàn)錯(cuò)誤。這是泛型中的協(xié)議問題。
0x06總結(jié)
C語言的泛型編程以void*充當(dāng)泛型類型,本質(zhì)上是泛型指針。
C語言的泛型編程不需要明白了一個(gè)泛型類型變量所占的內(nèi)存大小,這個(gè)是可以按照sizeof任意凸四邊形并傳來泛型函數(shù)。
C語言的泛型編程中要注意一點(diǎn)數(shù)組的偏移問題,void*的默認(rèn)偏移是1,對(duì)此絕大多數(shù)類型來說也是出錯(cuò)的,必須一一編程轉(zhuǎn)換。
C語言的泛型編程中可以使用fwrite函數(shù)進(jìn)行泛型變量的u盤拷貝和賦值。
C語言的泛型編程中也要再注意協(xié)議問題,但是C中就沒法讓其編寫函數(shù)參與定義,定義了,在其他語言中是可以建議使用現(xiàn)成的接口也可以協(xié)議。
請(qǐng)問什么叫SWIFTNO?
SWIFT地址是一個(gè)8或11位的字符串,是一個(gè)銀行在國際上的識(shí)別號(hào)碼。SWIFT是國際銀行金融電信協(xié)會(huì)英文首字母縮寫。SWIFT地址又被一般稱BIC(銀行識(shí)別碼)。SWIFT的編號(hào)規(guī)則一般是8位或11位,前四位為某銀行代碼,如中行是BKCH農(nóng)行是ABOC,下一刻四位是國別及地區(qū)代碼,如北京是CNBJ,后面肯定會(huì)有3位的數(shù)字或字母代碼,象是指具體詳細(xì)的分支行。