上篇博文(關於c語言結構體偏移的一點思考)對c語言中結構體偏移作了一些思考,發現博文中還有一些小的問題,沒有描述的足夠清楚,因此才萌生了本篇博文的想法。node
爲何不直接將本篇博文做爲上篇博文的一個「注」呢?主要有如下方面的緣由,一是使用一篇獨立的博文可以更好的闡述問題,從而完全的理解它;二是上篇博文的篇幅已經比較長,考慮到讀者的耐心,因此一篇博文不適合過長的篇幅;三是這個問題能夠做爲一個獨立的主題來探討,方便查閱;最後本着單一職責的原則,每篇博文討論一個特定的主題,對於主題的粒度大小,可酌情考慮。算法
那麼本篇博文主要探討什麼問題呢?從本文的標題咱們能夠看到,本文主要探討的是c語言中關於結構體成員變量的訪問方式。訪問結構體成員變量?如此簡單的問題,有什麼能夠思考的呢?很納悶也很奇怪。既然這樣,那就帶着這個奇怪的問題繼續閱讀吧。編程
咱們的探討仍是從一個簡單的示例開始:優化
已知結構體類型定義以下:spa
struct node_t { char a; int b; int c; };
且結構體1Byte對齊:.net
#pragma pack(1)
接下來咱們探討幾種訪問該結構體成員變量c的方式:指針
若是程序中定義了一個struct node_t類型的變量node以下:code
struct node_t node;
那麼咱們就能夠直接經過下面的方式來訪問成員變量c:blog
node.c
若是程序中定義了一個指向struct node_t類型的指針p_node以下:內存
struct node_t node; struct node_t *p_node = &node;
或者在堆上分配了一塊類型爲struct node_t的內存以下:
struct node_t *p_node= (struct node_t *)malloc(sizeof(struct node_t));
那麼咱們就可使用下面的方式來訪問成員變量c:
p_node -> c;
上述兩種訪問方式都是比較常見的,也是你們所熟悉的,下面咱們來探討一種你們不是特別熟悉也不是很常見的情形:
若是程序中只給定了一個內存地址數值addr_node,且該地址addr_node起始的一段內存,指向一塊類型爲struct node_t的內存,addr_node聲明以下:
unsigned long addr_node;
此時,咱們如何根據這塊內存地址來訪問成員變量c呢?
因爲咱們知道了該結構體的起始地址addr_node,因此咱們對其進行強制類型轉換,從而獲得一個指向該結構體的指針p_node:
struct node_t *p_node = (struct node_t *)addr_node;
接下來咱們就能夠經過情形2的方式來訪問成員變量c了;
情形3要傳達的意思是,咱們能夠經過一個具體的內存地址數值來訪問咱們的結構體成員變量;
爲何特意的指出情形3,由於咱們上一篇博文關於c語言結構體偏移的一點思考中使用了相似的用法:
((struct node_t *)0)->c
咱們經過內存地址0來訪問結構體struct node_t成員變量c,但這裏面有幾點須要說明一下:
1. 咱們並未對內存地址0作過任何內存相關操做,如解引用、賦值等,即內存地址編號0開始的一段內存無任何變化;
2. 咱們只是利用了編譯器的特性來幫助咱們計算結構體的偏移,僅僅是利用了編譯器的特性來計算而已;
3. 善於利用編譯器的一些特性來優化咱們的程序或系統;
本文主要介紹了c語言中關於訪問結構體成員變量的幾種方式,並對經過內存地址數值直接訪問結構體成員變量作了說明,解釋了上篇博文中可能產生疑問的一個問題。
若是您對算法或編程感興趣,歡迎掃描下方二維碼並關注公衆號「算法與編程之美」,和您一塊兒探索算法和編程的神祕之處,給您不同的解題分析思路。