獲取結(jié)構(gòu)體成員偏移量的方法

個(gè)人博客

所有文章除特別聲明外,均采用 CC BY-NC-SA 4.0 許可協(xié)議湃鹊。轉(zhuǎn)載請(qǐng)注明來(lái)自 nixgnauhcuy's blog菇用!

如需轉(zhuǎn)載字柠,請(qǐng)標(biāo)明出處忌堂!

不要站著調(diào)試程序露戒,那會(huì)使得你的耐心減半护蝶,你需要的是全神貫注⌒氖—— Dave Storer

前言

記錄工作中學(xué)習(xí)到的知識(shí)酿矢,在這里做些筆記榨乎,方便自己后面經(jīng)常溫習(xí)。


正文

為什么要獲取結(jié)構(gòu)體成員變量的偏移

我在做嵌入式工作時(shí)瘫筐,在已知要獲取信息的 flash 地址時(shí)蜜暑,需要取出相對(duì)應(yīng)的信息元素,這個(gè)時(shí)候時(shí)常需要知道結(jié)構(gòu)體相對(duì)于已知地址的偏移策肝,方便快捷的從 flash 中取出信息元素肛捍,所以時(shí)常使用這個(gè)方式。


方法

我們先用普通的方法獲取結(jié)構(gòu)體偏移之众,代碼如下:

#include <stdio.h>

typedef struct {
    int a;
    int b;
    int c;
}x_t;

void test(void)
{
    x_t p;
    printf("p_addr=%d\r\n", (int)&p);
    printf("p.a_addr=%d\r\n", (int)&p.a);
    printf("p.b_addr=%d\r\n", (int)&p.b);
    printf("p.c_addr=%d\r\n", (int)&p.c);

    printf("a_offset=%d\r\n", (int)&(p.a)-(int)&p);
    printf("b_offset=%d\r\n", (int)&(p.b)-(int)&p);
    printf("c_offset=%d\r\n", (int)&(p.c)-(int)&p);
}

int main(void)
{
    test();    
    return 0;
}

輸出結(jié)果:

image

可以看出篇梭,如果要獲取結(jié)構(gòu)體成員變量相對(duì)于結(jié)構(gòu)體的偏移,則需要先獲取結(jié)構(gòu)體地址酝枢,再獲取成員變量地址,成員變量地址減去結(jié)構(gòu)體地址悍手,才能獲取相應(yīng)的偏移帘睦。

我們?cè)儆昧硪环N方式獲取結(jié)構(gòu)體偏移,代碼如下:

#include <stdio.h>

typedef struct {
    int a;
    int b;
    int c;
}x_t;

void test1(void)
{
    x_t * p = 0;
    printf("a_offset = %d\n", (int)(&(p->a)));
    printf("b_offset = %d\n", (int)(&(p->b)));
    printf("c_offset = %d\n", (int)(&(p->c)));
}


int main(void)
{
    test1();
    return 0;
}

輸出結(jié)果:

image

這里先把結(jié)構(gòu)體地址指向地址 0x00000000坦康,這時(shí)候獲取成員變量相對(duì)于結(jié)構(gòu)體的偏移就輕松多了竣付,減少了一步操作,減少了計(jì)算量滞欠。


linux內(nèi)核代碼求結(jié)構(gòu)體成員變量偏移的方法

在內(nèi)核代碼 ./include/linux/stddef.h 文件中有如下定義:

image
#ifndef __CHECKER__
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

我們參考代碼編寫(xiě)后:

#include <stdio.h>

typedef struct
{
    int a;
    int b;
    int c;
}x_t;


#define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE*)0)->MEMBER))

void test2()
{
    printf("a_offset = %d\n", (int)&((x_t*)0)->a);
    printf("b_offset = %d\n", (int)&((x_t*)0)->b);
    printf("c_offset = %d\n", (int)&((x_t*)0)->c);
}

void test3()
{
    printf("a_offset = %d\n", offsetof(x_t, a));
    printf("b_offset = %d\n", offsetof(x_t, b));
    printf("c_offset = %d\n", offsetof(x_t, c));
}

int main(void)
{
    printf("test2():\r\n");
    test2();
    printf("test3():\r\n");
    test3();
    return 0;
}

輸出結(jié)果:

image

test2 和 test3 與上邊的 test1 方法其實(shí)是一樣的古胆,宏定義中的(TYPE*)0是一個(gè)空指針,如果使用空指針訪問(wèn)成員肯定造成段錯(cuò)誤筛璧,但是前面的 "&" 這個(gè)符號(hào)逸绎,表示我們僅僅取 MEMBER 字段的地址,而不是引用該字段內(nèi)容夭谤,因此不會(huì)造成段錯(cuò)誤棺牧。通過(guò)將結(jié)構(gòu)體地址指向 0x0 來(lái)獲得結(jié)構(gòu)體成員變量相對(duì)結(jié)構(gòu)體地址,即方便我們使用朗儒,也方便理解颊乘。


結(jié)尾

正如前言說(shuō)的,記錄工作中積累的點(diǎn)滴經(jīng)驗(yàn)醉锄,怕自己因?yàn)樯儆猛朔η模谶@里做個(gè)記錄,方便回顧恳不。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末檩小,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妆够,更是在濱河造成了極大的恐慌识啦,老刑警劉巖负蚊,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異颓哮,居然都是意外死亡家妆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門冕茅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)伤极,“玉大人,你說(shuō)我怎么就攤上這事姨伤∩谄海” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵乍楚,是天一觀的道長(zhǎng)当编。 經(jīng)常有香客問(wèn)我,道長(zhǎng)徒溪,這世上最難降的妖魔是什么忿偷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮臊泌,結(jié)果婚禮上鲤桥,老公的妹妹穿的比我還像新娘。我一直安慰自己渠概,他們只是感情好茶凳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著播揪,像睡著了一般贮喧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上猪狈,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天塞淹,我揣著相機(jī)與錄音,去河邊找鬼罪裹。 笑死饱普,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的状共。 我是一名探鬼主播套耕,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼峡继!你這毒婦竟也來(lái)了冯袍?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎康愤,沒(méi)想到半個(gè)月后儡循,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡征冷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年择膝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片检激。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肴捉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叔收,到底是詐尸還是另有隱情齿穗,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布饺律,位于F島的核電站窃页,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏复濒。R本人自食惡果不足惜腮出,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芝薇。 院中可真熱鬧,春花似錦作儿、人聲如沸洛二。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)晾嘶。三九已至,卻和暖如春娶吞,著一層夾襖步出監(jiān)牢的瞬間垒迂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工妒蛇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留机断,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓绣夺,卻偏偏與公主長(zhǎng)得像吏奸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陶耍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354