linux下链表实现的一些思考
2013-05-12 15:27
183 查看
看过linux的链表实现的方法,都知道用的很巧妙,尤其是list_entry宏的定义更是充分运用了C语言指针的灵活性。下面是具体的宏定义
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
ptr是指向list_head类型链表的指针,type为一个结构,而member为结构type中的一个域,类型为list_head,这个宏返回指 向type结构的指针。在内核代码中大量引用了这个宏,因此,搞清楚这个宏的含义和用法非常重要。
设有如下结构体定义:
typedef struct xxx
{
……//其他一些字段
.........
type1 member;
……
}type;
定义变量:
type a;
type * b;
type1 * ptr;
执行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
则可使b指向a,得到了a的地址。
如何做到的呢?
先看&((type *)0)->member:
把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。那么这个地址也就等于member域到结构体基地址的偏移字节数。再来看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):(char *)(ptr)使得指针的加减操作步长为一字节,不然加减步长就是sizeof(type),(unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。做减法就能得到结构体实例变量的首地址。
以上是随地可以百度到的解释,我的疑问是(char *)(ptr)这个地方的指针转换,装换成(char*)理所当然是为了使得指针偏移步长变为1字节,当这个地放后面的member偏移地址转换为unsigned long 我觉得把ptr也转换为unsigned long型更加有利于理解,这样使得前后格式一致完全转换为地址的加减运算,绕过指针偏移这一层面,对于代码调试如下
#define list_entry(ptr, type, member) \
((type *)((unsigned long)ptr-(unsigned long)(&((type *)0)->member)))
list_entry()宏
#define list_entry(ptr, type, member) \((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
ptr是指向list_head类型链表的指针,type为一个结构,而member为结构type中的一个域,类型为list_head,这个宏返回指 向type结构的指针。在内核代码中大量引用了这个宏,因此,搞清楚这个宏的含义和用法非常重要。
设有如下结构体定义:
typedef struct xxx
{
……//其他一些字段
.........
type1 member;
……
}type;
定义变量:
type a;
type * b;
type1 * ptr;
执行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
则可使b指向a,得到了a的地址。
如何做到的呢?
先看&((type *)0)->member:
把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。那么这个地址也就等于member域到结构体基地址的偏移字节数。再来看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):(char *)(ptr)使得指针的加减操作步长为一字节,不然加减步长就是sizeof(type),(unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。做减法就能得到结构体实例变量的首地址。
以上是随地可以百度到的解释,我的疑问是(char *)(ptr)这个地方的指针转换,装换成(char*)理所当然是为了使得指针偏移步长变为1字节,当这个地放后面的member偏移地址转换为unsigned long 我觉得把ptr也转换为unsigned long型更加有利于理解,这样使得前后格式一致完全转换为地址的加减运算,绕过指针偏移这一层面,对于代码调试如下
#include "stdafx.h" using namespace std; typedef struct list { struct list *next; struct list *prev; }list; typedef struct type { int a; char b; list member; }type; list* ptr; int _tmain(int argc, _TCHAR* argv[]) { type node; type *pp; ptr = &(node.member); node.a=4444; node.b='b'; pp = ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))); //cout<<((type *)((unsigned long)(ptr)-(unsigned long)(&((type *)0)->member))); cout<<pp<<endl<<pp->a<<endl<<pp->b<<endl; return 0; }个人觉得以下定义是不是更好一下
#define list_entry(ptr, type, member) \
((type *)((unsigned long)ptr-(unsigned long)(&((type *)0)->member)))
相关文章推荐
- 关于linux中nat实现的一些思考
- 关于linux中nat实现的一些思考
- Linux下的C语言编程——链表实现通讯录
- 链表中的一些算法,Java实现
- linux shell ssh实现自动登录,并且执行一些操作并返回到当前主机
- 一些思考方式——从continue按钮的实现暴露的设计问题
- 关于寻路算法的一些思考(3):A*算法的实现
- “1000万字符串,去掉重复”的一些思考和java实现
- Linux下链表常用实现方式
- Linux系统学习方法——写给小白 每个人都有心中向往的一些事情,而我,刚进实验室,看到师兄师姐在电脑前面噼里啪啦的敲代码,真的好羡慕,看着他们实现一个又一个的功能满心欢喜,我也很想尝试。后来了解到师
- 基于ElementUI的网站换主题的一些思考与实现
- 链表在linux中的实现
- 链表的c语言实现以及根据linux内核中链表的实现过程
- 关于《啊哈算法》模拟链表的一些思考
- 移植linux内核(3.0.13)的链表实现进windows下,VS编译通过。
- Linux双向循环链表的实现
- Linux下的C语言编程——链表实现队列操作
- 穷究链表(四)--链表实现前的思考
- Linux利用list_head结构实现双向链表
- 编程珠玑学习笔记 Aha算法 思考以及一些代码实现