void 型指標的高階用法,你掌握了嗎?

2022-09-16 02:18:08 字數 2694 閱讀 7838

void指標一般被稱為通用指標或叫泛指針。它是c語言關於純粹位址的一種約定。當某個指標是void型指標時,所指向的物件不屬於任何型別。因為void指標不屬於任何型別,則不可以對其進行算術運算,比如自增,編譯器不知道其自增需要增加多少。比如char *型指標,自增一定是指標指向的位址加1,short *型指標自增,則偏移2。

在c/c++中,在任意時刻都可以使用其它型別指標來代替void指標,或者用void指標來代替其他型別指標。由這些特性就可以衍生出很多比較有用的技巧。指標的本質,是其值為乙個位址,那麼延伸一下:

當使用關鍵字void宣告指標變數時,它將成為通用指標變數。 任何資料型別(char,int,float等)的任何變數的位址都可以賦值給void指標變數。

對指標變數的解引用,使用間接運算子*達到目的。 但是在使用空指標的情況下,需要轉換指標變數以解引用。 這是因為空指標沒有與之關聯的資料型別。 編譯器無法知道void指標指向的資料型別。 因此,要獲取由void指標指向的資料,需要使用在void指標位置內儲存的正確型別的資料進行型別轉換。

對於空指標的解引用,你如不信,就來看看栗子:

看到了吧,直接解引用編譯不過,因為編譯器蒙了。

但須注意的是:

所以做個型別轉換,修正如下:

另外,**如果函式型別可以是任意型別的指標,則需將其引數定義為void ***,例如string.h中關於記憶體操作的函式集:

__eff_nenw1nw2   __attributes   int       memcmp(const void *, const void *,

size_t);

__eff_nenr1nw2r1 __deprec_attrs void * memcpy(void *_restrict,

const void *_restrict,

size_t);

__eff_nenr1nw2r1 __deprec_attrs void * memmove(void *, const void *,

size_t);

__eff_nenr1r1 __deprec_attrs void * memset(void *, int, size_t);

在微控制器開發中,往往需要實現資料的非易失儲存。所謂非易失儲存,就是資料改寫後在掉電後仍然能保持。哪些是非易失儲存介質呢?比如eeprom,flash等都屬於非易失儲存介質。

比如乙個產品裡面有很多各種各樣的引數,且分布在各個子系統檔案中。舉個栗子:

/*模組a中有這樣乙個結構體需要非易失儲存*/

typedef struct _t_parast_paras;

t_paras sysparas;

/*模組b中有這樣乙個結構體需要非易失儲存*/

typedef struct _t_pidt_pid;

t_pid pidparas;

面對這樣乙個需求,要實現非易失儲存,我在將底層的eeprom/flash讀寫函式實現的基礎上,將上述應用資料按照一定順序儲存管理。那麼更為理想的方式是什麼呢?設計乙個模組專門負責儲存非易失資料。比如:

typedef struct _t_nv_layoutt_nv_layout;

/*引數對映表*/

t_nv_layout nvlayout=,/*引數對映記錄*/

,...

};/*引數對映表記錄條數*/

#define nv_record_number (sizeof(nvlayout)/sizeof(t_nv_layout))

void nv_load(t_nv_layout *playout,int nvaddr,int number);

void nv_store(t_nv_layout *playout,int nvaddr,int number);

將上述設計思想,利用uml描述一下:

在上述基礎上,我們只需要設計硬體層抽象,即可設計出乙個可行的、比較通用的nv管理子系統,這樣設計出的子系統忽略了業務資料,僅僅將其處理為資料,並不關心其業務意義。實現了業務邏輯與後台的隔離解耦。做到了通用性。這裡就比較巧妙的利用了void *指標的特性。如果對於該設計思想,在進一步延伸,將底層的抽象在做一層封裝,將更細節的底層實現細節隔離抽象,比如:

那麼怎麼做到底層抽象呢,我們可以利用函式指標定義統一的介面,具體部署時,只需要將實現函式的指標賦值給對應的函式指標即可,這樣就做到了介面的抽象統一。其實這就是驅動模型的乙個簡易雛形。

啟示:一些語言細節如果深入了解其背後的機理,可以得到很多比較巧妙的應用。

void指標 void 的用法

指標有兩個屬性 指向變數 物件的位址和長度 但是指標只儲存位址,長度則取決於指標的型別 編譯器根據指標的型別從指標指向的位址向後定址 指標型別不同則定址範圍也不同,比如 int 從指定位址向後尋找4位元組作為變數的儲存單元 double 從指定位址向後尋找8位元組作為變數的儲存單元 1.void指標...

void指標 void 的用法

指標有兩個屬性 指向變數 物件的位址和長度 但是指標只儲存位址,長度則取決於指標的型別 編譯器根據指標的型別從指標指向的位址向後定址 指標型別不同則定址範圍也不同,比如 int 從指定位址向後尋找4位元組作為變數的儲存單元 double 從指定位址向後尋找8位元組作為變數的儲存單元 1.void指標...

void指標 void 的用法

指標有兩個屬性 指向變數 物件的位址和長度 但是指標只儲存位址,長度則取決於指標的型別 編譯器根據指標的型別從指標指向的位址向後定址 指標型別不同則定址範圍也不同,比如 int 從指定位址向後尋找4位元組作為變數的儲存單元 double 從指定位址向後尋找8位元組作為變數的儲存單元 1.void指標...