2 5 泛型指標與型別轉換

2021-06-03 00:08:19 字數 2423 閱讀 5838

回想一下,在c中指標變數擁有與其它變數一樣的型別。之所以指標變數會有型別是因為當我們想獲取指標變數的值時,編譯器已經知道指標所指向的資料的型別,從而可以訪問相應的資料。但是,有些時候我們並不關心指標所指向的變數的型別。在這種情況下,我們就是可以使用泛型指標,泛型指標並不變數指定具體的資料型別。

通常情況下,c只允許相同型別的指標之間進行轉換。例如:乙個字元型指標sptr和乙個整型指標iptr,我們不允許把sptr轉換為iptr或把iptr轉換為sptr。但是,泛型指標能夠被轉換為任何型別,反之亦然。因此,如果有乙個泛型指標gptr,我可以把sptr轉換為gptr或者把gptr轉換為sptr。在c語言中,我們通常宣告乙個void指標來表示泛型指標。 

很多情況下void指標都是非常有用的。例如:c標準函式庫中的memcpy函式,它將一段資料從記憶體中的乙個地方複製到另乙個地方。由於memcpy可能用來複製任何型別的資料,所以將它的指標引數設定為void指標是非常合理的。void指標同樣可以用到其它普通的函式中去。例如:之前提到過的交換函式swap2,我們可以把函式引數改為void指標,這樣swap2就變成乙個可以交換任何型別資料通用交換函式,**如下:

#include #include int swap2(void *x, void *y, int size) 

void指標在用來實現資料結構時是非常有用的,因為我們可以通過void指標儲存和檢索任何型別的資料。我們再來看一下之前提到過的鍊錶結構listelmt,回想一下,這個結構包含兩個成員:data和next。如果data被宣告為乙個void指標,那麼data就可以指向任何型別的資料。從而,我們就可以使用listelmt結構來建立各種不同資料型別的鍊錶。 

在第5章裡,定義了乙個鍊錶的操作函式list_ins_next,它的功能是將乙個指向data的指標元素插入到鍊錶中:

int list_ins_next(list *list, listelmt *element, void *data);

要將指標iptr引用的資料插入到名為list的整型鍊錶中,c語言允許我們將整型指標iptr賦值給引數data,因為data是乙個void指標。

retval = list_ins_next(&list, element, iptr);

當然,當從乙個鍊錶中刪除資料時,必須使用正確的資料型別來檢索要被刪除的資料。這樣做是為了保證當我們想對資料進行操作時資料的型別是正確的。正如之前所述,從乙個鍊錶中刪除元素的函式list_rem_next,它的第三個引數是乙個指向void指標的指標:

int list_rem_next(list *list, listelmt *element, void **data);

想要從list中刪除乙個整型變數,並且element是要刪除元素的引用,我們用如下呼叫方式。當函式返回時,iptr指向了被刪除的資料。這是由於此操作改變了指標本身,將位址傳遞給了指標iptr,,使其指向了被刪除的資料。

retval = list_rem_next(&list, element, (void **)&iptr);

同時,此函式呼叫包含乙個將iptr臨時轉換為乙個指向void指標的指標的過程。正如我們將在下一節所看到的,型別轉換是c語言中的一種特殊的轉換機制,它允許我們臨時把一種型別的變數轉換為另一種型別的變數。在這裡,型別轉換是必要的,因為c語言中雖然乙個void指標與其它型別的指標相相容,但乙個指向void指標的指標卻並不一定與其它型別的指標相容。

要將型別為t的變數t轉換成s型別,只需要在t前加上用括號括上的s。例如:要將乙個整型指標iptr轉換為乙個浮點型指標fptr,我們在整型指標加上乙個用括號括起來的浮點指標即可,如下所示:

fptr = (float *)iptr;

(通常來說將乙個整型指標轉換成乙個浮點指標是一種危險的做法,但在這裡我們僅僅用這個例子做乙個型別轉換的示例而已。)在型別轉換之後,iptr與fptr都指向了同一塊記憶體位址。但是,從這個位址取到什麼型別的值是由我們用什麼型別的指標訪問它所決定的。

對於泛型指標來說型別轉換非常重要,因為只有告訴泛型指標是通過何種型別來訪問位址時,泛型指標才能正確取到值。這是由於泛型指標不會告訴編譯器它指向的是何種型別資料,所以編譯器既不知道哪個位址要被訪問,也不知道多少位元組的資料會被訪問。當將泛型指標賦值給其他型別的指標時,使用型別轉換也是一種很好的**自注釋方法。儘管這裡的轉換並不是必須的,但這樣做能大大提高程式的可讀性。

當轉換指標時,我們對記憶體中的對齊方式必須特別注意。具體來說,我們需要知道,指標的型別轉換會暗地裡改變計算機本身的對齊方式。很多計算機對對齊的方式有要求,因為某些硬體的優化可以使訪問記憶體更有效率。所以,如果有乙個非按字對齊的void指標,當我們將它轉換為乙個整型指標並試圖獲取它的值時,程式可能在執行時出現異常。

ps:

Swift之泛型型別與泛型引數

import foundation func swaptwoints inout a int,inout b int func swaptwostrings inout a string,inout b string func swaptwodoubles inout a double,inout ...

泛型與集合型別

說起泛型時,就不得不說到泛型集合型別 因為使用反省能夠極大的提高集合型別的效能和安全性.為了看看使用泛型能為集合型別帶來什麼好處,先看看不用泛型時集合型別的表現 最典型的非泛型集合型別就是 arraylist了,這裡便以它為例作為介紹 考慮一下下面的 arraylist list new array...

C 泛型型別 泛型方法

泛型會宣告型別引數 泛型的消費者需要提供型別引數來把佔位符型別填充 public class stack var stack newstack int stack.push 2 stack.push 3 int x stack.pop 2int y stack.pop 3stack open typ...