一个宏定义函数

iEverX 2012-07-18 02:03:29
这时Linux内核里面的一个宏定义,container_of看不懂,真心求教!!

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

/**
* 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) );})
...全文
1007 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
Yeah517716172 2012-11-09
  • 打赏
  • 举报
回复
好贴啊! 另开贴了吗? 我想看看啊
引用 11 楼 everax 的回复:
引用 10 楼 的回复:引用 7 楼 的回复: 那个宏和你的完全两码事……那是对结构体及其成员的操作,你这个哪里来的结构体 确实不是同一回事。。但是形式结构上是一样的 这个宏是包在打括号中的两个语句。。怎么能使得第二条语句的值赋给大括号之前的变量呢。 就像这个,把宏展开,编译不过的 C/C++ code struct Node { int……
iEverX 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

引用 7 楼 的回复:

那个宏和你的完全两码事……那是对结构体及其成员的操作,你这个哪里来的结构体

确实不是同一回事。。但是形式结构上是一样的
这个宏是包在打括号中的两个语句。。怎么能使得第二条语句的值赋给大括号之前的变量呢。
就像这个,把宏展开,编译不过的
C/C++ code
struct Node {
int a;
int b;
};
struct N……
[/Quote]

好像是少写了东西。。已经是另一个问题了。稍后另开贴问
iEverX 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

那个宏和你的完全两码事……那是对结构体及其成员的操作,你这个哪里来的结构体
[/Quote]
确实不是同一回事。。但是形式结构上是一样的
这个宏是包在打括号中的两个语句。。怎么能使得第二条语句的值赋给大括号之前的变量呢。
就像这个,把宏展开,编译不过的
struct Node {
int a;
int b;
};
struct Node anode = {12, 34};
int *q = &(anode.a);
struct Node * pnode = { const int *m = (q); (struct Node *) ((char *) m - offsetof(struct Node, q));}
iEverX 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

那个宏和你的完全两码事……那是对结构体及其成员的操作,你这个哪里来的结构体
[/Quote]

确实不是同一回事。。但是形式结构上是一样的
这个宏是包在打括号中的两个语句。。怎么能使得第二条语句的值赋给大括号之前的变量呢。
就像这个,把宏展开,编译不过的
struct Node {
int a;
int b;
};
struct Node anode = {12, 34};
int *q = &(node,a);
sruct Node * pnode = { const int *m = (q); (struct Node *) ((char *) m - offsetof(struct Node, q));}

lx3275852 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

container_of(ptr, type, member) 就是 已知 member的地址 求 type的地址的一个宏

C/C++ code

struct A
{
int a;
int b;
}

size_t o = offsetof(A, b);

A *p = (A*)malloc(A);
int *pB = p->b;
那么 ((char*)pB-(cha……
[/Quote]


宏的功能是求一个struct 的 某个 member 的地址偏移量吧。。
Corner 2012-07-18
  • 打赏
  • 举报
回复
那个宏和你的完全两码事……那是对结构体及其成员的操作,你这个哪里来的结构体
iEverX 2012-07-18
  • 打赏
  • 举报
回复
还有一个小问题。。
int x = {double b; (int) 3.5;}
这个应该不能通过编译的。。
但是对于这个宏来说,结构是一样的。。我自己敲了一遍,也总是编译错误。。为嘛Linux还能跑起来呢?
iEverX 2012-07-18
  • 打赏
  • 举报
回复
还有一个问题,就是。。

比如说
int x = {const double y = 89; (int) 3.6;}
这个应该是编译不通过的。。
但是这个宏定义为在内核里为什么可以
q = container_of(a, struct b, c);
这样用呢??
Corner 2012-07-18
  • 打赏
  • 举报
回复
假设我们有一个结构体

typedef struct
{
int a;
float b;
}Test_Struct;

首先看这个

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

((TYPE *)0)是将0转换为指定类型指针,比如Test_Struct,那么我们获得了一个Test_Struct指针
&((TYPE *)0)->MEMBER),MEMBER是上述结构的成员,比如b,那么这一段就是获取了b的地址,因为结构体指针是由0准换而来,所以b的地址也可以看做是b和结构体的偏移

所以((size_t) &((TYPE *)0)->MEMBER)这一段是求指定结构体的指定成员在结构体中的偏移。比如offsetof(Test_Struct, b)的结果是4(因为在它之前只有一个int变量)

然后看这个

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

((type *)0)->member 上面已经讲过,是取指定结构体的指定成员,比如b
typeof( ((type *)0)->member )获取该成员的类型,b的类型是float
const typeof( ((type *)0)->member ) *__mptr 所以此处相当于const float *__mptr = (ptr);即定义了一个const float型变量
(char *)__mptr - offsetof(type,member) 此处是将声明的成员地址(即传递进来的ptr的地址)减去成员在结构体中的偏移地址,所以获得结构体地址
(type *)( (char *)__mptr - offsetof(type,member) );对上述结构体地址进行类型转换,转为结构体类型


所以该宏命令的作用是给定一个成员变量获取它所在的结构体变量指针
比如

Test_Struct test;
test.a = 123;
test.b = 23.456;
container_of(&test.b, Test_Struct, b);

这样可以获取test变量指针
夏天__ 2012-07-18
  • 打赏
  • 举报
回复
[url请看这里:Linux内核入门(三)—— C语言基本功 =http://blog.csdn.net/olillian/article/details/7264997][/url]
hotpos 2012-07-18
  • 打赏
  • 举报
回复
container_of(ptr, type, member) 就是 已知 member的地址 求 type的地址的一个宏


struct A
{
int a;
int b;
}

size_t o = offsetof(A, b);

A *p = (A*)malloc(A);
int *pB = p->b;
那么 ((char*)pB-(char*)p) == o

所以 p == (A*)((char*)pB - o), (A*)((char*)pB - o) == p。

container_of(pB, A, b)
展开后为

const typeof( ((A*)0)->b )* __mptr = pB;
(A*)((char*)__mptr - offsetof(A, b))

因为 __mptr = pB, offsetof(A, b) = o
所以 上面的式子可化简为
(A*)((char*)pB - o) => p



夏天__ 2012-07-18
  • 打赏
  • 举报
回复
就是一个宏定义;
当函数里面出现container_of(ptr, type, member)时,直接用后面的替换;

(ptr, type, member)里面都是参数,对应后面的式子;

也可以理解container_of(ptr, type, member)为一个函数;带参数;

1. const typeof( ((type *)0)->member ) *__mptr = (ptr);

是定义一个__mptr指针变量,类型和member的类型一样

typeof是获得一个变量的类型,((type *)0)->member 则是tpye类型中的member 变量,一般type为结构体类型,member 则为其中的变量

这里的0只是作为一个临时的指针地址用,任何可以表示地址的数字都可以代替0

#define container_of(ptr, type, member) ({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr); /
(type *)( (char *)__mptr - offsetof(type,member) );})


1.(type*)0->member为设计一个type类型的结构体,起始地址为0,编译器将结构体的起始的地址加上此结构体成员变量的偏移得到此结构体成员变量的地址,由于结构体起始地址为0,所以此结构体成员变量的偏移地址就等于其成员变量在结构体内距离结构体开始部分的偏移量。即:&(type*)0->member就是取出其成员变量的偏移地址。而其等于其在结构体内的偏移量:即为:(size_t)(& ((type*)0)->member)经过size_t的强制类型转换后,其数值为结构体内的偏移量。该偏移量这里由offsetof()求出。

2.typeof( ( (type *)0)->member )为取出member成员的变量类型。用其定义__mptr指针;ptr为指向该成员变量的指针。__mptr为member数据类型的常量指针,其指向ptr所指向的变量处。

3.(char*)__mptr转换为字节型指针。(char *)__mptr - offsetof(type,member))用来求出结构体起始地址(为char *型指针),然后(type *)( (char *)__mptr -offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。

这就是从结构体某成员变量指针来求出该结构体的首指针。指针类型从结构体某成员变量类型转换为该结构体类型。

69,374

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧