1. 程式人生 > 其它 >(轉載)計算結構體首地址的技巧

(轉載)計算結構體首地址的技巧

struct ABC
{
int a;
int b;
int c;
};

+----------+ <------我們需要計算的是這個地址。
| a(4Byte) |
+----------+ <------這個地址是已知的。
| b(4Byte) |
+----------+
| c(4Byte) |
+----------+
通過上圖可看出,只需要把當前知道的成員變數的地址ptr,減去它在結構體當中相對偏移量(4),就得到了結構體的首地址(ptr-4).
設計一個type型別的結構體,起始地址為0,編譯器將結構體的起始的地址加上此結構體成員變數的偏移得到此結構體成員變數的偏移地址,由於設計的結構體起始地址為0,所以此結構體成員變數的偏移地址就等於其成員變數在結構體內的距離結構體開始部分的偏移量。

Linux核心中,用兩個非常巧妙地巨集實現了,一個是offsetof巨集,另一個是container_of巨集:
1.offsetof巨集(獲得一個結構體變數成員在此結構體中的偏移量)
#define offsetof(struct_type, member_name) ((size_t) & ((struct_type *)0)->member_name )
【分析】:
(1) 該巨集中,struct_type為結構體型別,member_name為結構體內的變數名
(2) ((struct_type *)0) 是欺騙編譯器說有一個指向結構struct_type 的指標,其地址值0
(3) &((struct_type *)0)->member_name 是要取得結構體struct_type中成員變數member_name的地址.
(4) 最後將其值強轉為size_t,即轉化為一個常數值,而不是將其當作地址進行使用。
因為基址為0,所以,這時member_name的地址當然就是member_name在struct_type中的偏移了。

2. container_of巨集(從結構體[struct_type]某成員變數[member_name]指標[member_addr]來求出該結構體[struct_type]的首指標)
#define container_of(member_addr, struct_type, member_name) ({const typeof( ((struct_type *)0)->member_name ) *__mptr = (member_addr); (struct_type *)( (char *)__mptr - offsetof(struct_type,member_name) );})或者直接定義#define container_of(member_addr, struct_type, member_name) ((struct_type *)( (char *)member_addr - offsetof(struct_type,member_name) ))
【分析】:
(1)typeof( ( (struct_type *)0)->member )為取出member_name成員的變數型別。
(2) 定義__mptr指標member_addr為指向該成員變數的指標(即指向member_addr所指向的變數處)
(3) (char *)__mptr - offsetof(struct_type,member_name)) 用該成員變數的實際地址減去該變數在結構體中的偏移,來求出結構體起始地址。
(4) ({ })這個擴充套件返回程式塊中最後一個表示式的值。

轉載於:https://www.cnblogs.com/eric-geoffrey/p/3811630.html