亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

C語言中結構體偏移及結構體成員變量訪問方式的問題討論

2020-01-26 14:35:35
字體:
來源:轉載
供稿:網友

c語言結構體偏移
示例1

我們先來定義一下需求:

已知結構體類型定義如下:

struct node_t{ char a; int b; int c;};

且結構體1Byte對齊

#pragma pack(1)

求:

結構體struct node_t中成員變量c的偏移。

注:這里的偏移量指的是相對于結構體起始位置的偏移量。

看到這個問題的時候,我相信不同的人腦中浮現的解決方法可能會有所差異,下面我們分析以下幾種可能的解法:

方法1

如果你對c語言的庫函數比較熟悉的話,那么你第一個想到的肯定是offsetof函數(其實只是個宏而已,先姑且這樣叫著吧),我們man 3 offsetof查看函數原型如下:

 #include <stddef.h>  size_t offsetof(type, member);

有了上述的庫函數,我們用一行代碼就可以搞定:

offsetof(struct node_t, c);

當然這并非本文探討的重點,請繼續閱讀。

方法2

當我們對c語言的庫函數不熟悉的時候,此時也不要著急,我們依然可以使用我們自己的方法來解決問題。

最直接的思路是:【結構體成員變量c的地址】 減去 【結構體起始地址】

我們先來定義一個結構體變量node:

struct node_t node;

接著來計算成員變量c的偏移量:

(unsigned long)(&(node.c)) - (unsigned long)(&node)
&(node.c)為結構體成員變量c的地址,并強制轉化為unsigned long;

&node為結構體的起始地址,也強制轉化為unsigned long;

最后我們將上述兩值相減,得到成員變量c的偏移量;

方法3

按照方法2的思路我們在不借助庫函數的情況下,依然可以得到成員變量c的偏移量。但作為程序員,我們應該善于思考,是不是可以針對上面的代碼做一些改進,使我們的代碼變得更簡潔一些?在做具體的改進之前,我們應該分析方法2存在哪些方面的問題。

相信不用我多說,細心的你一定已經察覺到,方法2中最主要的一個問題是我們自定義了一個結構體變量node,雖然題目中并未限制我們可以自定義變量,但當我們遇到比較嚴且題目中不允許自定義變量的時候,此時我們就要思考新的解決方法。

在探討新的解決方法之前,我們先來探討一個有關偏移的小問題:

小問題

這是一道簡單的幾何問題,假設在座標軸上由A點移動到B點,如何計算B相對于A的偏移?這個問題對于我們來說是非常的簡單,可能大部分人都會脫口而出并得到答案為B-A。

那么這個答案是否完全準確呢?比較嚴謹的你覺得顯然不是,原因在于,當A為坐標原點即A=0的時候,上述答案B-A就直接簡化為B了。

這個小小的簡單的問題,對于我們來說有什么啟示呢?

我們結合方法2的思路和上述的小問題,是不是很快就得到了下面的關聯:

(unsigned long)(&(node.c)) - (unsigned long)(&node)

B - A
我們小問題的思路是當A為坐標原點的時候,B-A就簡化為B了,那么對應到我們的方法2,當node的內存地址為0即(&node==0)的時候,上面的代碼可簡化為:

(unsigned long)(&(node.c))
由于node內存地址==0了,所以

node.c  //結構體node中成員變量c
我們就可以使用另外一種方式來表達了,如下:

((struct node_t *)0)->c
上述代碼應該比較好理解,由于我們知道結構體的內存地址編號為0,所以我們就可以直接通過內存地址的方式來訪問該結構體的成員變量,相應的代碼的含義就是 獲取內存地址編號為0的結構體struct node_t的成員變量c。

此時,我們的偏移求法就消除了struct node_t node這個自定義變量,直接一行代碼解決,:

(unsigned long)(&(((struct node_t *)0)->c))
上述的代碼相對于方法2是不是更簡潔了一些。

這里我們將上面的代碼功能定義為一個宏,該宏的作用是用來計算某結構體內成員變量的偏移(后面的示例會使用該宏):

#define OFFSET_OF(type, member) (unsigned long)(&(((type *)0)->member))

使用上面的宏,就可以直接得到成員變量c在結構體struct node_t中的偏移為:

OFFSET_OF(struct node_t, c)

示例2

和示例1一樣,我們先定義需求如下:

已知結構體類型定義如下:

struct node_t{ char a; int b; int c;};

int *p_c,該指針指向struct node_t x的成員變量c

結構體1Byte對齊

#pragma pack(1)

求:

結構體x的成員變量b的值?

拿到這個問題的時候,我們先做一下簡單的分析,題目的意思是根據一個指向某結構體成員變量的指針,如何求該結構體的另外一個成員變量的值。

那么可能的幾種解法有:

方法1

由于我們知道結構體是1Byte對齊的,所以這道題最簡單的解法是:

*(int *)((unsigned long)p_c - sizeof(int))
上述代碼很簡單,成員變量c的地址減去sizeof(int)從而得到成員變量b的地址,然后再強制轉換為int *,最后再取值最終得到成員變量b的值;

方法2

方法1的代碼雖然簡單,但擴展性不夠好。我們希望通過p_c直接得到指向該結構體的指針p_node,然后通過p_node訪問該結構體的任意成員變量了。

由此我們得到計算結構體起始地址p_node的思路為:

【成員變量c的地址p_c】減去【c在結構體中的偏移】

由示例1,我們得到結構體struct node_t中成員變量c的偏移為:

(unsigned long)&(((struct node_t *)0)->c)
所以我們得到結構體的起始地址指針p_node為:

(struct node_t *)((unsigned long)p_c - (unsigned long)(&((struct node_t *)0)->c))
我們也可以直接使用示例1中定義的OFFSET_OF宏,則上面的代碼變為:

(struct node_t *)((unsigned long)p_c - OFFSET_OF(struct node_t, c))
最后我們就可以使用下面的代碼來獲取成員變量a,b的值:

p_node->a

p_node->b
我們同樣將上述代碼的功能定義為如下宏:

#define STRUCT_ENTRY(ptr, type, member) (type *)((unsigned long)(ptr)-OFFSET_OF(type, member))

該宏的功能是通過結構體任意成員變量的指針來獲得指向該結構體的指針。

我們使用上面的宏來修改之前的代碼如下:

STRUCT_ENTRY(p_c, struct node_t, c)

p_c為指向結構體struct node_t成員變量c的指針;

struct node_t結構體類型;

c為p_c指向的成員變量;

注:

上述示例中關于地址運算的一些說明:

int a = 10;int * p_a = &a;

設p_a == 0x95734104;

以下為編譯器計算的相關結果:

  • p_a + 10 == p_a + sizeof(int)*10 =0x95734104 + 4*10 = 0x95734144
  • (unsigned long)p_a + 10 == 0x95734104+10 = 0x95734114
  • (char *)p_a + 10 == 0x95734104 + sizeof(char)*10 = 0x95734114

從上述三種情況,相信你應該能體會到我所要表達的意思了。

結構體成員變量訪問方式
訪問結構體成員變量?如此簡單的問題,有什么可以思考的呢?很納悶也很奇怪。既然這樣,那就帶著這個奇怪的問題繼續閱讀吧。

示例3

我們的探討還是從一個簡單的示例開始:

已知結構體類型定義如下:

struct node_t { char a; int b; int c;};

且結構體1Byte對齊:

#pragma pack(1)

接下來我們探討幾種訪問該結構體成員變量c的方式:


情形1

如果程序中定義了一個struct node_t類型的變量node如下:

struct node_t node;

那么我們就可以直接通過下面的方式來訪問成員變量c:

node.c

情形2

如果程序中定義了一個指向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;

情形3

上述兩種訪問方式都是比較常見的,也是大家所熟悉的,下面我們來探討一種大家不是特別熟悉也不是很常見的情形:

如果程序中只給定了一個內存地址數值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的一點說明

((struct node_t *)0)->c
我們通過內存地址0來訪問結構體struct node_t成員變量c,但這里面有幾點需要說明一下:

1. 我們并未對內存地址0做過任何內存相關操作,如解引用、賦值等,即內存地址編號0開始的一段內存無任何變化;

2. 我們只是利用了編譯器的特性來幫助我們計算結構體的偏移,僅僅是利用了編譯器的特性來計算而已;

3. 善于利用編譯器的一些特性來優化我們的程序或系統;

結論

本文主要介紹了c語言中關于訪問結構體成員變量的幾種方式,并對通過內存地址數值直接訪問結構體成員變量做了說明,解釋了上篇博文中可能產生疑問的一個問題。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品视频一区二区三区四| 亚洲春色另类小说| 欧美日韩精品中文字幕| 8090理伦午夜在线电影| 在线观看国产精品91| 国产精品人成电影在线观看| 亚洲综合大片69999| 亚洲国产精品yw在线观看| 久久69精品久久久久久久电影好| 欧美日韩亚洲一区二| 高跟丝袜欧美一区| 欧美精品一区三区| 国产视频综合在线| 欧美成人全部免费| 揄拍成人国产精品视频| 在线视频日韩精品| 欧美国产第二页| 欧美日韩国产综合视频在线观看中文| 国产日韩欧美在线视频观看| 成人a在线视频| 黑人巨大精品欧美一区二区免费| 久久精品视频va| 一区二区福利视频| 精品福利在线看| 久久国产精品久久久久久| 日韩国产欧美精品在线| 国产精品免费视频xxxx| 精品国产欧美一区二区五十路| 国产精品美女免费| 精品视频在线导航| 日韩精品视频免费在线观看| 成人国产精品一区| 国产在线精品成人一区二区三区| 永久免费精品影视网站| 久久久电影免费观看完整版| 在线午夜精品自拍| 97精品免费视频| 日韩欧美综合在线视频| 亚洲最新中文字幕| 国外成人在线直播| 日韩专区在线播放| 日韩欧美高清视频| 欧美中文在线观看国产| 精品国产视频在线| 日韩精品视频免费专区在线播放| 色偷偷88888欧美精品久久久| 亚洲国产精品久久精品怡红院| 亚洲一区二区国产| 亚洲专区在线视频| 国产欧美日韩专区发布| 欧美成人精品激情在线观看| 国产在线播放不卡| 久久天天躁夜夜躁狠狠躁2022| 中文字幕不卡av| 精品国内自产拍在线观看| 疯狂蹂躏欧美一区二区精品| 69av在线播放| 亚洲黄色在线观看| 久久久久久成人精品| 69av视频在线播放| 中文字幕日韩在线观看| 日韩电影免费观看中文字幕| 中文国产成人精品久久一| 日韩国产在线播放| …久久精品99久久香蕉国产| 久久久综合免费视频| 日韩电影大全免费观看2023年上| 欧美国产日韩一区| 欧美日在线观看| 久久久久久中文字幕| 欧美孕妇性xx| 日韩美女写真福利在线观看| 日韩成人性视频| 国产亚洲精品成人av久久ww| 欧美黑人xxx| 日韩在线免费视频| 久久成人这里只有精品| 性欧美办公室18xxxxhd| 国产精品久久久久9999| 日本在线观看天堂男亚洲| 久久人人爽人人爽人人片av高请| 久久久视频精品| 国产精品成人一区| 欧美日韩成人在线视频| 久久全球大尺度高清视频| 一夜七次郎国产精品亚洲| 亚洲自拍偷拍区| 欧美精品在线播放| 亚洲福利视频网站| 日本成人激情视频| 亚洲老司机av| 欧美精品中文字幕一区| 亚洲mm色国产网站| 亚洲精品久久在线| 久久久久久久激情视频| 成人淫片在线看| 国产精品久久久久一区二区| 欧美性生交xxxxx久久久| 97在线观看视频| 亚洲另类xxxx| 992tv成人免费视频| 成人www视频在线观看| xxx一区二区| 91精品久久久久久久久久另类| 26uuu日韩精品一区二区| 国产成人+综合亚洲+天堂| 亚洲天堂av网| 国产色视频一区| 日韩欧中文字幕| 欧美大片在线看免费观看| 在线精品高清中文字幕| 91免费看国产| 精品免费在线视频| 日本久久久久久久| 国产精品高清在线观看| 亚洲国产精品中文| 久久天天躁夜夜躁狠狠躁2022| 亚洲美女免费精品视频在线观看| 久久精品成人一区二区三区| 久久久久久综合网天天| 日韩中文字幕视频在线观看| 亚洲欧美另类在线观看| 欧美成人在线网站| 欧美日韩中文字幕日韩欧美| 清纯唯美日韩制服另类| www.亚洲一区| 国产在线一区二区三区| 国产精品91久久久久久| 亚洲国产成人在线播放| 亚洲精品白浆高清久久久久久| 成人免费大片黄在线播放| 欧美区二区三区| 久久成人人人人精品欧| 中文字幕在线成人| 亚洲国产精品va在看黑人| 国产精品99导航| 欧美二区乱c黑人| 97国产精品人人爽人人做| 97在线视频免费播放| 国产精品久久久久久亚洲调教| 亚洲影院在线看| 欧美日韩在线免费| 欧美激情欧美激情在线五月| 精品国产精品自拍| 韩曰欧美视频免费观看| 日韩高清电影免费观看完整版| 亚洲欧美国产精品专区久久| 亚洲人成伊人成综合网久久久| 国产欧美日韩91| 91亚洲国产成人久久精品网站| 亚洲人成77777在线观看网| 亚洲美女性生活视频| 大量国产精品视频| 国产精品一久久香蕉国产线看观看| 日韩av一卡二卡| 国产日韩欧美在线看| 日韩欧美综合在线视频| 日韩成人中文字幕在线观看| 奇门遁甲1982国语版免费观看高清| 欧美激情视频一区二区三区不卡| 中文字幕v亚洲ⅴv天堂| 精品一区二区三区电影| 欧美性xxxxx极品娇小| 亚洲一区二区三区四区视频|