從Linux核心代碼中學習獲得結構體成員位移量的方法 .__Linux

來源:互聯網
上載者:User

文章轉自點擊開啟連結

Content

0. 引子

1. 舉例

(1) 代碼

(2) 檢查結果

(3) 為什麼從0開始。

(4) 從非0地址開始的結果

2. 小結

 

0. 引子

 

在linux-2.26.23版的核心代碼中,./include/linux/stddef.h檔案中有如下定義。

00020: #undef offsetof00021: #ifdef  compiler_offsetof00022: #define offsetof(TYPE,MEMBER)  compiler_offsetof(TYPE,MEMBER)00023: #else00024: #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)00025: #endif00026: #endif /* KERNEL  */00027:00028: #endif

compiler_offsetof不是筆者關心的內容,第二個宏定義即為本文討論的方法。

這個宏定義很好解釋:將0地址強制轉換為TYPE類型指標,並取得MEMBER,然後擷取該MEMBER地址,最後將該地址強制轉換為表示大小的整數。該整數即為該成員的位移量。

 

1. 舉例

 

(1) 代碼

00001: / **00002: * test the offset of a member of a struct00003: */00004:00005: #include <stdio.h>00006:00007: typedef struct00008: {00009:    int x;00010:    int y;00011:    int z;00012: } Point;00013:00014: //#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)- >MEMBER)00015: #define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE*)0)- >MEMBER))00016:00017: void test1()00018: {00019:    int x = (size_t) &((Point*)0)- >x;00020:    int y = (size_t) &((Point*)0)- >y;00021:    int z = (size_t) &(((Point*)0)- >z);00022:    printf("offset: x = %d, y = %d, z = %d\n", x, y, z);00023: }00024:00025: void test2()00026: {00027:    printf("Point.x offset = %d\n", offsetof(Point, x));00028:    printf("Point.y offset = %d\n", offsetof(Point, y));00029:    printf("Point.z offset = %d\n", offsetof(Point, z));00030: }00031:00032: int main(int argc, char** argv)00033: {00034:    test1();00035:    printf("\n");00036:    test2();00037:    return 0;00038: }00039:

在該例子中,筆者借用Linux核心的方法,兩種方式實現

(2) 檢查結果

# ./offsetofoffset: x = 0, y = 4, z = 8Point.x offset = 0Point.y offset = 4Point.z offset = 8

無需說明,這個結果是正確的。


(3) 為什麼從0開始。

從第1節敘述的該方法的思想中,可以看出,從0開始的目的是不需要在獲得某個成員的地址後減去結構體的起始地址。

下面我們看看從非0開始的結果。


(4) 從非0地址開始的結果

修改test1()函數,如下。

00017: void test1()00018: {00019:    int x = (size_t) &((Point*)1000)- >x;00020:    int y = (size_t) &((Point*)1000)- >y;00021:    int z = (size_t) &(((Point*)1000)- >z);00022:    printf("offset: x = %d, y = %d, z = %d\n", x, y, z);00023: }
結果如下。

# ./offsetofoffset: x = 1000, y = 1004, z = 1008Point.x offset = 0Point.y offset = 4Point.z offset = 8

可以看出,如果從非0開始,實際上獲得的是該成員的實際地址(當然,該實際地址是相對於給定的起始地址來說的,並非真實的記憶體位址)。該實際地址減去給定的起始地址後也可得成員的位移量。


2. 小結


本文借用Linux核心的方法,舉例敘述了擷取結構體成員位移量的方法。Linux核心中還有N多好的結構和演算法,筆者以後慢慢講述。

遇到問題要思考,且是深入思考。學習核心要學習其設計思想和方法,記錄是要整理自己的思路,以備後忘。


去年和最近面試過很多人,問到這個題目,但極少人能答上來,這種問題可是基本功啊。還不知道如何擷取結構體成員位移量的同學,敲打鍵盤,試一下吧。:)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.