offsetofとcontainer_ofマクロ分析

2911 ワード

offsetofマクロ:構造体メンバーの構造体に対するオフセット位置container_of:構造体メンバーのアドレスに基づいて構造体のアドレスを取得する

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