offsetofとcontainer_ofマクロ分析
2911 ワード
offsetofマクロ:構造体メンバーの構造体に対するオフセット位置container_of:構造体メンバーのアドレスに基づいて構造体のアドレスを取得する
プロトタイプ:
プロトタイプ:linux-4.18.5
ネット上で見られるのは、次のバージョンです.
第1部:
したがって
offsetofマクロ
プロトタイプ:
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
(TYPE *)0
は非常に巧みで、コンパイラに構造体TYPEを指すポインタがあることを教えて、そのアドレスは0で、それからそのポインタのMEMBERアドレス&((TYPE *)0)->MEMBER
を取って、ベースアドレスは0なので、この時取得したMEMBERのアドレスは構造体TYPEの中のオフセット量に相当します.Example: #include
#include
#include
struct TYPE{
int mem;
int member;
};
int main()
{
struct TYPE type;
printf("&type = %p
", &type);
printf("&type.member = %p
", &type.member);
printf("&((struct type *)0)->member = %lu
", ((size_t)&((struct TYPE *)0)->member) );
printf("offsetof(struct TYPE member) = %zd
", offsetof(struct TYPE, member));
return 0;
}
/*
result:
&type = 0x7ffc1104a110
&type.member = 0x7ffc1104a114
&((struct type *)0)->member = 4
offsetof(struct TYPE member) = 4
*/
container_ofマクロ
プロトタイプ:linux-4.18.5
/**
* 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) ({ \
void *__mptr = (void *)(ptr); \
BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
ネット上で見られるのは、次のバージョンです.
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
第1部:
void *__mptr = (void *)(ptr);
またはconst typeof( ((type *)0)->member ) *__mptr = (ptr);
の違いはmptrのタイプは1つがvoid*,1つがtype*である.void*は分かりやすいので、type*を見てみましょう.typeofキーワードの役割は変数を返すタイプです.簡単に理解すると、kernelでのGCC typeofの使用--C言語の「コンパイル時マルチステート」を参照してください.int a;
typeof(a) b; // int b;
typeof(&a) c; // int* c;
したがって
const typeof( ((type *)0)->member ) *__mptr = (ptr);
の役割はtypeofによって構造体メンバーメンバーメンバーのタイプを取得し、このタイプのポインタ変数__を定義することである.mptrをptrに割り当てます.第2部:(type *)( (char *)__mptr - offsetof(type,member) )
、offsetof
マクロによりtypeにおけるmemberのオフセットを算出し、その後memberの実際のアドレス__mptr
からオフセットを減算してtypeの開始アドレスを得る.offsetof
マクロのExampleについても上記の点を検証できます:&type.member = 0x7ffc1104a114 - &((struct type *)0)->member = 4 = &type = 0x7ffc1104a110