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;
}