?

container_of的作用的通過結(jié)構(gòu)體成員變量地址獲取這個結(jié)構(gòu)體的地址。內(nèi)核函數(shù)調(diào)用常常給函數(shù)傳入的是結(jié)構(gòu)體成員地址,然后在函數(shù)里面又想使用這個結(jié)構(gòu)體里面的其他成員變量,所以就引發(fā)了問題。

static void sensor_suspend(struct early_suspend *h)                   
{
struct sensor_private_data *sensor =
container_of(h, struct sensor_private_data, early_suspend);
if (sensor->ops->suspend)
sensor->ops->suspend(sensor->client);
}


early_suspend是sensor_private_data 里面的一個成員,通過這個成員的地址獲取sensor_private_data結(jié)構(gòu)體變量的地址,從而調(diào)用里面的成員變量client。

如何使用container_of

container_of需要傳入三個參數(shù),第一個參數(shù)是一個指針,第二個參數(shù)是結(jié)構(gòu)體類型,第三個是對應(yīng)第二個參數(shù)里面的結(jié)構(gòu)體里面的成員。

container_of(ptr, type, member)

ptr:表示結(jié)構(gòu)體中member的地址 h

type:表示結(jié)構(gòu)體類型 struct sensor_private_data
member:表示結(jié)構(gòu)體中的成員 early_suspend type里面一定要有這個成員,不能瞎搞啊

返回結(jié)構(gòu)體的首地址



#yyds干貨盤點(diǎn)#Linux驅(qū)動中container_of的作用_成員變量?

#yyds干貨盤點(diǎn)#Linux驅(qū)動中container_of的作用_成員變量_02

一些知識

({})、第一個先說這個表達(dá)式,很多人可能懂,可能在很多地方見到這個表達(dá)式,但是自己卻沒有注意,這個表達(dá)式返回最后一個表達(dá)式的值。比如x=({a;b;c;d;}),最終x的值應(yīng)該是d。

typeof獲取變量的類型

這個我們很少看到,這個關(guān)鍵字是C語言關(guān)鍵字的拓展,返回變量的類型,具體可以看GCC里面的介紹 ??https://gcc.gnu.org/onlinedocs/gcc/Typeof.html??

++Another way to refer to the type of an expression is with typeof. The syntax of using of this keyword looks like sizeof, but the construct acts semantically like a type name defined with typedef.++

代碼例子:

void main(void)
{
int a = 6;
typeof(a) b =9;
printf("%d %d/n",a,b);
}


(struct st*)0的作用

現(xiàn)在我們需要量一個結(jié)構(gòu)體的長度,我們也可以用尺子來量,我們只要找到這個0刻度的位置就可以了。同理,即使我們不知道0刻度位置,我們首尾刻度相減一樣可以計算出結(jié)構(gòu)體的長度。 但是在C語言里什么是尺子呢?你想到的可能是sizeof,不幸的是,這個并不能滿足我們的需要,所以才有了(struct st *),這個當(dāng)作尺子真的再好不過了。

struct st{
int a;
int b;
}*p_st,n_st;

void main(void)
{
printf("%p/n",&((struct st*)0)->b);
}


上面的代碼

(struct st*)0


這個的意思就是把這個結(jié)構(gòu)體放到0刻度上面開始量了,然后量到哪里呢?

&((struct st*)0)->b)


這個就體現(xiàn)出來了,量到b的位置。所以上面的輸出應(yīng)該是4。

看完上面的解釋,應(yīng)該知道下面這兩個代碼的功能是一樣的。

typeof ((struct st*)0)->b) c; // 取b的類型來聲明c
int c;


其實(shí)不只是對于0,用其他數(shù)字一樣是有效的,比如下面的代碼,編譯器關(guān)心的是類型,而不在乎這個數(shù)字。

printf("%p/n",&((struct st*)4)->b  -4 );


如果現(xiàn)在需要你把一個數(shù)組的首地址設(shè)置為0,要怎么做呢?

先思考一下,假設(shè)這里延遲了幾分鐘。

代碼如下:

struct A {
short array[100];
};

int main(int argc, char *argv[])
{
int i = 10;

A* a = (A*)0;
printf("%p %d %d/n",a,sizeof(short), &a->array[20]);
getchar();
return 1;
}
//輸出 00000000 2 40


offsetof(TYPE, MEMBER)

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


size_t 這個有不懂的可以百度下,就是unsigned 的整數(shù),在32位和64位下長度不同,所以這個offsetof就是獲取結(jié)構(gòu)體的偏移長度

const int* p的作用

上面的宏定義里面還有一個小知識點(diǎn)

const typeof( ((type *)0)->member ) *__mptr


上面的代碼可以簡寫成

const int * __mptr


這個說明什么問題呢?這個說明__mptr指向的整型數(shù)據(jù)是一個const(常數(shù))。 這就涉及到兩外兩個知識

int * const __mptr;//表示__mptr的值不能改變
//和
const int * const __mptr; //表示__mptr不能改變而且指向的內(nèi)容也不能改變


container_of 剖析

看完上面的幾個知識點(diǎn),再來看container_of這個宏就顯得非常清晰了。我把解析部分寫在下面的代碼注釋里面。

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
#define container_of(ptr, type, member) ({ /
const typeof( ((type *)0)->member ) *__mptr = (const typeof( ((type *)0)->member ) *)(ptr); /
(type *)( (char *)__mptr - offsetof(type,member) );})
//-----分割線------
struct st{
int a;
int b;
}*pt;
//用這個來舉例
container_of(&pt->a,struct st,a)
const typeof( ((struct st *)0)->a ) *__mptr = (const typeof( ((struct st *)0)->a ) *)(&pt->a);
const int *__mptr = (int *)(&pt->a);//第一句解析完,實(shí)際上就是獲取a的地址。
(type *)( (char *)__mptr - offsetof(type,member) );
//這個變成
(struct st *)( (char *)__mptr - ((unsigned int) &((struct st*)0)->a));
//這句的意思,把a(bǔ)的地址減去a對結(jié)構(gòu)體的偏移地址長度,那就是結(jié)構(gòu)體的地址位置了。

?