C語言如何實現泛型程式設計?

roc_guo發表於2021-04-07

C語言如何實現泛型程式設計?C語言如何實現泛型程式設計?

這裡介紹一種方法——透過無型別指標 void*。

看下面的一個實現交換兩個元素內容的函式 swap,以整型 int 為例:

void swap(int* i1,int* i2){  
         int temp;  
         temp = *i1;  
         *i1 = *i2;  
         *i2 = temp;  
}

當你想交換兩個 char 型別時,你還得重寫一個引數型別為 char 的函式,是不是能用無型別的指標來作為引數呢?看如下改動:

void swap(void *vp1,void *vp2){  
       void temp = *vp1;  
       *vp1 = *vp2;  
       *vp2 = temp;  
}

這段程式碼是錯誤的,是通不過編譯的。首先,變數是不能宣告為 void 無型別的。而你不知道呼叫此函式傳進的引數是什麼型別的,無法確定一種型別的宣告。同時,不能將 * 用在無型別指標上,因為系統沒有此地址指向物件大小的資訊。在編譯階段,編譯器無法得知傳入此函式引數的型別的。這裡要想實現泛型的函式,需要在呼叫的地方傳入相關要交換的物件的地址空間大小 size,同時利用在標頭檔案 string.h 中定義的 memcpy() 函式來實現。改動如下:

void swap(void *vp1,void *vp2,int size){  
      char buffer[size];//注意此處gcc編譯器是允許這樣宣告的
      memcpy(buffer,vp1,size);  
      memcpy(vp1,vp2,size);  
      memcpy(vp2,buffer,size);  
}

在呼叫這個函式時,可以像如下這樣呼叫(同樣適用於其它型別的 x、y):

int x = 27,y = 2;  
swap(&x,&y,sizeof(int));

下面看另一種功能的函式:

int lsearch(int key,int array[],int size){
      for(int i = 0;i < size; ++i)
                  if(array[i] == key)
                           return i;
     return -1;
}

此函式在陣列 array 中查詢 key元素,找到後返回它的索引,找不到返回 -1。

如上,也可以實現泛型的函式:

void* lsearch(void* key, void *base, int n, int elemSize){
    for(int i = 0;i < n; ++i){
        void *elemAddr = (char *)base+i*elemSize;
        if(memcmp(key, elemAddr, elemSize) == 0)
            return elemAddr;
    }
    return NULL;
}

程式碼第三行:將陣列的首地址強制轉換為指向 char 型別的指標,是利用 char 型別大小為1位元組的特性,使 elemAddr 指向此"泛型"陣列的第 i-1 個元素的首地址。因為之前已經說過,此時你並不知道你傳入的是什麼型別的資料,系統無法確定此陣列一個元素有多長,跳向下個元素需要多少位元組,所以強制轉換為指向 char 的指標,再加上引數傳入的元素大小資訊和累加數i的乘積,即偏移地址,即可得此陣列第 i-1 個元素的首地址。這樣使無論傳入的引數是指向什麼型別的指標,都可以得到指向正確元素的指標,實現泛型程式設計。

函式 memcmp() 原型:int memcmp(void *dest,const void *src,int n),比較兩段長度為n首地址分別為 dest、src 的地址空間中的內容。

此函式在陣列 base 中查詢 key 元素,找到則返回它的地址資訊,找不到則返回 NULL。

如果使用函式指標,則可以實現其行為的泛型:

void *lsearch(void *key,void *base,int n,int elemSize,int(*cmpfn)(void*,void*,int)){
    for(int i = 0;i < n; ++i){
        void *elemAddr = (char *)base+i*elemSize;
        if(cmpfn(key,elemAddr,elemSize) == 0)
            return elemAddr;
    }
    return NULL;
}

再定義一個要呼叫的函式:

int intCmp(void* elem1,void* elem2){
        int* ip1 = elem1;
        int* ip2 = elem2;
        return *ip1-*ip2;
}

看如下呼叫:

int array[] = {1,2,3,4,5,6};
int size = 6;
int number = 3;
int *found = lsearch(&number,array,size,sizeof(int),intCmp);
if(found == NULL)
         printf("NO\n");
else
         printf("YES\n");

C 語言也可以實現一定的泛型程式設計,但這樣是不安全的,系統對其只有有限的檢查。在程式設計時一定要多加細心。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2766776/,如需轉載,請註明出處,否則將追究法律責任。

相關文章