当前位置:首页 > 服务端 > Linux下的Container_of

Linux下的Container_of

Linux下的Container_of

看内核代码的时候看到了container_of宏,写的真是挺巧妙的,直接起到了this指针的功能

#define container_of(ptr, TYPE, MEMBER)({   \
    const typeof(((TYPE *)0)->MEMBER) *_mptr = (ptr); \
    (TYPE*)((char*)_mptr - offsetof(TYPE, MEMBER));  \
})

当时主要有两个疑问:

  • 为什么要有个临时变量_mptr?直接使用ptr不就可以了?
  • 为什么要给mptr强转成char*?

写了段代码
Container_of的测试代码:

#include <stdio.h>

#define offsetof(TYPE, MEMBER)({(size_t) &(((TYPE *)0)->MEMBER);})

#define container_of(ptr, TYPE, MEMBER)({   \
    const typeof(((TYPE *)0)->MEMBER) *_mptr = (ptr); \
    (TYPE*)((char*)_mptr - offsetof(TYPE, MEMBER));  \
})

struct stA{
    char a;
    int b[3];
    double c;
};

int main (void) 
{
    struct stA A;
    double* x = &(A.c);

    printf("%p\n",&A);
    printf("%p <-- %p\n", x, container_of(x, struct stA, c));
    return 0; 
}

这份代码输出如下:
0x7fff5718ebd0
0x7fff5718ebe0 <-- 0x7fff5718ebd0

如果去掉_mptr前的(char),输出则为:
0x7fff519e6bd0
0x7fff519e6be0 <-- 0x7fff519e6b60
因为C语言指针变量的差值是根据指针变量类型来计算的,_mptr是double类型(8字节),实际上的结果是8
offsetof(TYPE, MEMBER)),这样计算地址当然会出错。

而对于

const typeof(((TYPE *)0)->MEMBER) *_mptr = (ptr);

一句的解释,参考了这篇文章的描述:
这句话主要作用是在编译时,能够让编译器检查ptr的类型和MEMBER的类型是否匹配,如果不匹配则产生相应的告警。
例如,

#include <stdio.h>

#define offsetof(TYPE, MEMBER)({(size_t) &(((TYPE *)0)->MEMBER);})

#define container_of(ptr, TYPE, MEMBER)({   \
    const typeof(((TYPE *)0)->MEMBER) *_mptr = (ptr); \
    (TYPE*)((char*)_mptr - offsetof(TYPE, MEMBER));  \
})

struct stA{
    char a;
    int b[3];
    double c;
};

int main (void) 
{
    struct stA A;
    double* x = &(A.c);

    printf("%p\n",&A);
    printf("%p <-- %p\n", x, container_of(x, struct stA, a)); //这里把成员变量名错写成a
    return 0; 
}

编译器在编译时会告警:

warning: incompatible pointer types initializing 'const typeof (((struct stA *)0)->a) *' (aka 'const char *') with an expression of type 'double *' [-Wincompatible-pointer-types]

如果改成这样:

#define container_of(ptr, TYPE, MEMBER)({   \
    (TYPE*)((char*)ptr - offsetof(TYPE, MEMBER));  \
})

编译直接通过,这类错误难以发现。

找了下博客园里有这么篇文章,对于实现细节已经讲的挺详细了。

作者:NumberSix
来源链接:https://www.cnblogs.com/numbersix/p/4304600.html

版权声明:
1、Java侠(https://www.javaxia.com)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。





本文链接:https://www.javaxia.com/server/125735.html

分享给朋友: