Linux内核学习之C语言中用结构体成员找结构体

前言
啊,看不懂题目什么意思吗?来,老夫给你分解一下
Linux内核学习 之 C语言中 以结构体成员找结构体。重点就是加粗的部分。
啊,什么,还是不太理解。说的再详细点:
给你一个结构体成员的地址,让你找这个结构体的首地址。’
举个栗子:

typedef struct node
{
    
    
    double x;
    int d;
    char c;
}Node;

给你一个Node型的结构体变量中的一个成员d的地址,让你找这个结构体变量的地址。

啊,还是不懂。。
“给我滚。。。。。。”

废话说的有些多了哈,言归正传,我们知道,在C语言中知道了结构体变量的地址(也就是结构体变量),引用其成员是很简单的,直接用->符号就可以。但是如果给我们这个结构体变量成员的地址(某个中间的地址),让你找这个结构体变量地址(首地址),一般还真不太好找。

最近学习Linux内核的时候,看到内核中很多部分都用到了这个机制(内核中实现这个机制的是一个叫做container of()的函数,准确点叫宏定义函数),所以仔细研究了一下。

原理
网上有很多讲的比较好的教程,我在这就不再造轮子了。简要概括一下。
我们知道,结构体变量中的成员在C语言中是按照顺序一个一个存放的,如果给你一个中间变量d的地址(pd),计算结构体变量的首地址,我们需要知道首地址和这个地址pd之间的地址差(offset)。

那么问题来了,我们如何知道这个offset呢? 你又没给多余的条件?
答:内核编写的大佬们用了一个小trick,把结构体变量首地址先放到0地址处(通过强制地址转换),那么pd的地址不就是等于offset的值了吗。牛逼不?

具体的详细说明可以自行百度,这里可以给大家一个推荐
                    container of()函数简介

一个具体的小实验
下面来个小实验,满足我那“碰碰碰”的好奇心。

```cpp
#include<stdio.h>

#define MAXSIZE 100

typedef struct
{
    
    
    double x;
    int d;
    char c;


}Node;


int main()
{
    
    
    Node t,*p,*tp;
    int *pd;
    int offset;

	//结构体成员赋值
    t.c = 'a';
    t.d = 10;
    t.x = 12.5;

    pd =&(t.d);         //得到目的结构体变量的成员地址(int型)
    p = (Node*)0;       //p指向虚拟的Node结点(0地址)
    offset =(size_t)&(p->d);      //得到偏移量
    tp = (Node*)((char*)pd-offset);    //得到首地址,(注意,这个地方pd需要转化为char*,因为是地址相减)

    //不用t变量访问,用得到的结构体变量首地址进行访问
    printf("p->data:%d,p->x:%lf,p->c:%c\n",tp->d,tp->x,tp->c);


    return 0;
}

在这里插入图片描述
其余的不多说,只说中间的一点:

tp = (Node*)((char*)pd-offset);
1
这一句话为什么要用(char*)强制转化为(char*)类型?
答:因为指针相减见的是代表指针的那个单元长度,并不是真正的地址。如
p–(p指向一个double型的数据);那么p减的是一个double的长度。

猜你喜欢

转载自blog.csdn.net/liuqingsongmsdn2014/article/details/108351750