C语言#Linux-- 计算结构体成员偏移和成员反向计算结构体地址(container_of)

代码复制于Linux内核:tools/include/linux/kernel.h
作用图:
在这里插入图片描述

功能:

  • 1、typeof是编译器扩展的特性(推断出类型),https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  • 2、container_of:1、先报地址强制转换为特定成员地址,变量前_为了不冲突 2、计算成员偏移字节 3、再转换为char*,为了进行字节单位的地址运算 4、最终转换为结构体类型即可。。。 5、整个宏是一个复合语句,最后一个子表达式的值就是整个表达式的值。(也是编译器扩展特性,https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html)
#include <stdio.h>
#include <stdlib.h>



//复制于:tools/include/linux/kernel.h

#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

#ifndef container_of
/**
 * 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) ({			\
	const typeof(((type *)0)->member) * __mptr = (ptr);	\
	(type *)((char *)__mptr - offsetof(type, member)); })
#endif

#ifndef max
#define max(x, y) ({				\
	typeof(x) _max1 = (x);			\
	typeof(y) _max2 = (y);			\
	(void) (&_max1 == &_max2);		\
	_max1 > _max2 ? _max1 : _max2; })
#endif


#define P_INT(a) printf("The int is: [%d]\n",a)


typedef struct TestBuffer {
    int a;
    double b;
    struct InBuffer{
        int aa;
        double bb;
    }c;
}TestBuffer;


struct InBuffer* getInBuffer() {
    TestBuffer *tbp = malloc(sizeof(*tbp));
    if(tbp == NULL) {
        exit(-1);
    }
    printf("在一个函数内,所以我知道 tbp的地址: [%p].\n",tbp);
    return &tbp->c; 
}


int main(int argc, char const *argv[])
{
    typeof(int) a = 10;
    P_INT(a);

    int offSetC = offsetof(TestBuffer, c);
    printf("成员c的地址,从结构体的地址开始算,偏移了 [%d] 个字节.\n", offSetC);

    struct InBuffer *inbp = getInBuffer();
    TestBuffer *tbp = container_of(inbp, TestBuffer, c);
    printf("在一个函数外,我只知道成员的地址,但是container_of可以帮我获取 结构体的地址: [%p].\n", tbp);

    free(tbp);
    return 0;
}

运行结果:

在这里插入图片描述

预处理后的语句,gcc -E

int main(int argc, char const *argv[])
{
// ....
    struct InBuffer *inbp = getInBuffer();
    TestBuffer *tbp = ({ const typeof(((TestBuffer *)0)->c) * __mptr = (inbp); (TestBuffer *)((char *)__mptr - ((size_t) &((TestBuffer *)0)->c)); });

//....
    return 0;
}