學過C語言的人都知道,我們可以通過struct定義自己的資料集合,從而實現對資料的封裝功能。
在實際的項目實踐中,struct定義的結構隨處可見。使用struct並不難,網上也有很多介紹struct的文章。
從如構定義到如何使用,講得很詳細。在此我就不多講。
這裡主要介紹在struct中如何擷取成員變數的位移以及通過成員變數的地址擷取struct的起始地址。
第二個問題是緊密依賴第一個問題的。
1. 擷取成員變數的位移。
直接上代碼吧:
#define offset_of(type, field) ( (unsigned int)&(((type *)(0))->field) )
這個宏對於剛開始學習C語言的人來說是比較困難的。
要理解這個宏,首先要理解宏定義到底是怎麼一回事,還有struct是怎麼一回事,還有指標的用法。
簡單解釋一下這個宏:
如果我們定義一個struct:
typedef struct{
int a;
int b;
} A;
那麼offset_of(A, b)就會輸出b相對於起始地址的位移。
& -- 這是取地址符號,表示擷取當前變數的地址。
0 -- 這是這個宏中最核心的地方。我們知道,對於一個struct, 比如說上面的A, &A->b代表了b的地址, 如果我們想得到b相對於A的位移,那麼&A->b - &A就可以得到。
但如是&A就是0呢。那麼&A->b不就是位移了嗎。
好了,當我們有了擷取成員變數相對位移的宏。如果已知成員變數的地址,那我們也可以輕鬆得擷取該成員所在結構體的首地址。
代碼如下:
#define container_of(ptr, type, field) (type *)((char *)ptr - offset_of(type, field))
我們只需要把該成員變數的地址減去你相對於首地址的位移,不就是該結構體的首地址了麼。
好了,不多說了,結出一個完整的執行個體:
// testConsole.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <time.h>#include <stdio.h>#include <stdlib.h>#define offset_of(type, field) ( (unsigned int)&(((type *)(0))->field) )#define container_of(ptr, type, field) (type *)((char *)ptr - offset_of(type, field))typedef struct{ int a; int b; char c; int d;}package_t;int main(){ package_t pkg; int *p; p = (int *)&pkg.d; printf("offset of 'd' is %d.\n", offset_of(package_t, d)); printf("The addr of pkg = 0x%x.\n", &pkg); printf("The addr of d's container = 0x%x.\n", container_of(p, package_t, d)); return 0;}