讓我們先看看相關宏
/**
* list.h
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* stddef.h
*/
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
/*
* kernel.h
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
這裡要獲得整個結構體的首地址,分為以下幾步:
1) 將0強制轉換為我們想要的類型,然後擷取成員的類型,定義成員指標的類型(由編譯器做),typeof( ((type *)0)->member ) *__mptr
2) __mptr指向ptr,在list_entry裡面就是 list_head *
3)當有了list_head地址後,就可以減去這個地址的位移獲得結構體的頭
下面是獲得位移:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
1)首先將0轉換為想要的類型,然後擷取它的member成員,這裡就是list_head
2)將member(list_head)的地址,在這裡為0的位移,其實就是member相對於TYPE的位移。其實這裡全是由編譯器完成
這裡舉個例子:
struct test{
int member;
struct list_head list;
};
int main(int argc, char *argv[])
{
struct test test_ls, *p_test_head;
p_test_head = container_of(&test_ls.list, struct test, list);
/*
第一天語句:typeof( ((type *)0)->member ) *__mptr = (ptr); 這裡__mptr指向&test_ls.list
第二條語句:(type *)( (char *)__mptr - offsetof(type,member) );}) 這裡用__mptr - &((struct test*)0)->member) == (__mptr - 4)
*/
return 0;
}
這裡很多人認為沒有必要這麼麻煩的,其實一開始很多人都不習慣,包括我。但是仔細研究後發現,這裡確實抽象的很好,尤其是核心需要一個統一結構時,具有很好的通用性,而不至於出錯。
記憶體對齊:
記憶體對齊是編譯器對變數儲存的一個特殊處理。為了提高CPU的儲存速度,編譯器對一些變數的起始地址做了對齊處理。
在預設情況下,編譯器規定各成員變數存放的起始地址相對於結構的起始地址的位移量必須為該變數的類型所佔用的位元組數的倍數。
分配的位元組數為結構體中佔用空間最大的類型所佔用的位元組數的整數倍(r如果結構體中還有結構體,他們之間可以合并的)
#pragma pack (value)來告訴編譯器粒度,在VC++中也可以通過工程--》設定 來設定
#pragma pack() 來取消對齊
在linux可以在結構體後面加__attribute__((packed))來設定為最小記憶體, __attribute__((aligned))屬性使被設定的對象佔用更多的空間。這個屬性與你的編譯器有關,我在我的機器上使用__attribute__ ((aligned (8))),就無效
struct S {
unsigned short a[3];
} __attribute__ ((aligned (4)));
我想看看netfilter,今天就到這裡吧,限於水平,文章難免有誤,如果這篇文章有錯,請給我留言!