1. offsetof
1.1 offsetof介紹
定義:offsetof在linux內核的include/linux/stddef.h中定義。
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
說明:獲得結構體(TYPE)的變量成員(MEMBER)在此結構體中的偏移量。
(01) ( (TYPE *)0 ) 將零轉型爲TYPE類型指針,即TYPE類型的指針的地址是0。
(02) ((TYPE *)0)->MEMBER 訪問結構中的數據成員。
(03) &( ( (TYPE *)0 )->MEMBER ) 取出數據成員的地址。由於TYPE的地址是0,這裏獲取到的地址就是相對MEMBER在TYPE中的偏移。
(04) (size_t)(&(((TYPE*)0)->MEMBER)) 結果轉換類型。對於32位系統而言,size_t是unsigned int類型;對於64位系統而言,size_t是unsigned long類型。
1.2 offsetof示例
代碼(offsetof_test.c)
#include <stdio.h>
// 獲得結構體(TYPE)的變量成員(MEMBER)在此結構體中的偏移量。
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
struct student
{
char sex;
int age;
char name[20];
};
void main()
{
int sex_offset, age_offset, name_offset;
sex_offset = offsetof(struct student, sex);
age_offset = offsetof(struct student, age);
name_offset = offsetof(struct student, name);
printf("sex_offset = %d\n", sex_offset);
printf("age_offset = %d\n", age_offset);
printf("name_offset = %d\n", name_offset);
}
結果:
說明:簡單說說"爲什麼age的偏移值是4,而不是1"。我的運行環境是linux系統,32位的x86架構。這就意味着cpu的數據總線寬度爲32,每次能夠讀取4字節數據。gcc對代碼進行處理的時候,是按照4字節對齊的。所以,即使name_offset是char(一個字節)類型,但是它仍然是4字節對齊的!
1.3 offsetof圖解
TYPE是結構體,它代表"整體";而MEMBER是成員,它是整體中的某一部分。
將offsetof看作一個數學問題來看待,問題就相當簡單了:已知'整體'和該整體中'某一個部分',而計算該部分在整體中的偏移。