當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 嵌入式云IOT技術(shù)圈
[導(dǎo)讀]1 offsetof宏的原理以及作用 在使用container_of宏之前,我們先來(lái)了解下offsetof這個(gè)宏,它在Linux內(nèi)核里的源碼是這個(gè)樣子: #define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER) 1.1 offsetof宏的工作原理 虛擬一個(gè)TYPE類型的結(jié)構(gòu)體變量,通過(guò)TYPE.

















1 offsetof宏的原理以及作用

在使用container_of宏之前,我們先來(lái)了解下offsetof這個(gè)宏,它在Linux內(nèi)核里的源碼是這個(gè)樣子:

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

1.1 offsetof宏的工作原理

虛擬一個(gè)TYPE類型的結(jié)構(gòu)體變量,通過(guò)TYPE.MEMBER的方式來(lái)訪問(wèn)MEMBER成員,進(jìn)而得到MEMBER成員相對(duì)于整個(gè)結(jié)構(gòu)體首地址的偏移量。

這句話理解起來(lái)看似很抽象,&((TYPE *)0)->MEMBER相當(dāng)于得到了成員的偏移減去0地址偏移,也就是結(jié)構(gòu)體的首地址,進(jìn)而就得到了該成員相當(dāng)于整個(gè)結(jié)構(gòu)體的偏移量,接下來(lái)寫(xiě)一個(gè)例子就明白了:

1.2 offsetof宏編程案例

#include <stdio.h>
#define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER)
#pragma pack(4)
struct ptr
{
char a ;
short b ;
int c ;
double d ;
};
#pragma pack()
int main(void)
{
struct ptr Pt ;
printf("ptr:%d\n",sizeof(struct ptr));
//相對(duì)地址偏移量
int offset = offsetof(struct ptr,a);
printf("offset:%d\n",offset);
int offset1 = offsetof(struct ptr,b);
printf("offset1:%d\n",offset1);
int offset2 = offsetof(struct ptr,c);
printf("offset2:%d\n",offset2);
int offset3 = offsetof(struct ptr,d);
printf("offset3:%d\n",offset3);
return 0 ;
}

運(yùn)行結(jié)果:

在案例中,我們以默認(rèn)4字節(jié)對(duì)齊得到的4個(gè)結(jié)構(gòu)體變量在結(jié)構(gòu)體中的偏移,明白了offsetof宏如何使用,就解決了我們的大疑問(wèn)了,我們來(lái)看看container_of宏怎么使用吧。

2 Linux container_of宏的原理以及作用

Linux中的container_of宏長(zhǎng)如下這個(gè)樣子,那它有什么作用呢?我們來(lái)詳細(xì)剖析一下。

#define container_of(ptr, type , member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr) ; \
(type *)((char *)__mptr - offsetof(type,member)) ;})

2.1 container_of宏的工作原理

先用typeof獲取變量的數(shù)據(jù)類型,也就是member成員的類型,然后將member這個(gè)成員 的指針轉(zhuǎn)成自己類型的指針,再?gòu)膐ffsetof相減,就得到整個(gè)結(jié)構(gòu)體變量的首地址了,再將該地址強(qiáng)制轉(zhuǎn)化為type *。

接下來(lái)寫(xiě)一個(gè)關(guān)于container_of宏的編程案例:

2.2 container_of宏編程案例

#include <stdio.h>
#include <stdlib.h>
//獲取結(jié)構(gòu)體成員相對(duì)于結(jié)構(gòu)體的偏移
#define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER)
//通過(guò)獲取結(jié)構(gòu)體中的某個(gè)成員的,反推該結(jié)構(gòu)體的指針
#define container_of(ptr, type , member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr) ; \
(type *)((char *)__mptr - offsetof(type,member)) ;})
//讓結(jié)構(gòu)體默認(rèn)以四字節(jié)對(duì)齊
#pragma pack(4)
struct ptr
{
char a ;
short b ;
int c ;
double d ;
};
#pragma pack()

int main(void)
{
struct ptr Pt ;
struct ptr *pt ;
printf("ptr:%d\n",sizeof(struct ptr));//16
//獲取結(jié)構(gòu)體的首地址
printf("ptr:%p\n",&Pt); //0028FEA8
Pt.a = 'a';
Pt.b = 2 ;
Pt.c = 4 ;
Pt.d = 12.04 ;
//通過(guò)container_of獲取結(jié)構(gòu)體的首地址
pt = container_of(&Pt.c, struct ptr , c);
printf("pt:%p\n",pt);
printf("a:%c\n",pt->a) ;
printf("b:%d\n",pt->b) ;
printf("c:%d\n",pt->c) ;
printf("d:%.2lf\n",pt->d);
return 0 ;
}

運(yùn)行結(jié)果:

往期精彩

談?wù)勛霎a(chǎn)品、做項(xiàng)目以及標(biāo)準(zhǔn)化相關(guān)的話題

推薦一個(gè)非常好的項(xiàng)目管理工具

帶串口屏顯示的Bootloader

分享一個(gè)很好用的按鍵組件


若覺(jué)得本次分享的文章對(duì)您有幫助,隨手點(diǎn)[在看]并轉(zhuǎn)發(fā)分享,也是對(duì)我的支持。

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉