C语言那些小秘密之链表(三).pdfVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
C 语言的那些小秘密之链表 (三) 在开始写 linux 内核双向循环链表之前,我一直在想我要不要用长篇大论的文字来描述 linux 内核双向循环链表呢?经过认真的思考之后,我否决了用枯燥的文字向读者描述 linux 内核双向循环链表的想法,因为对于编程语言来说我相信大多数的读者都应该不喜欢面对枯 燥的文字,更喜欢看到代码,同时那也是读者阅读文字后想要实现的东西,所以我决定在这 里采用代码加上适当的文字描述的方法来进行讲解,这就使得我不可能用一篇的篇幅来讲解 完,所以会写两篇文章来讲解这个知识点。希望读者能够坚持看完,学会以后在应用程序中 写双向循环链表时,不用再自己去编写那些麻烦的操作函数,充分利用 linux 内核里已经提 供的遍历链表的操作函数。 特此说明:我会把我在文章中编写代码时候用到的头文件 list.h 上传到我的空间,免积分下 载,有需要的读者可以自己去下载,当然也可以自己上网下载或者从自己安装的 linux 系统 中得到。下载地址:/user/bigloomy 懂了 linux 内核里双向循环链表的实现方式之后我们不得不惊叹它的实现是如此的巧妙,为 了读者能够顺利的和我一起走完这次 linux 内核双向循环链表之旅,在此之前我特地为之写 了一篇 《C 语言的那些小秘密之字节对齐》的文章,如果你发现在本篇文章中有些地方不懂 的时候,你可以回过去看看 《C 语言的那些小秘密之字节对齐》再来接着继续往下继续全文 的阅读。 由于我们在linux 内核中有大量的数据结构都需要用到双向循环链表。若再采用以往那种传 统双向循环链表的实现方式,我们不得不为这些数据结构维护各自的链表,并且为每个链表 都要设计插入、查找、删除等操作函数。这是因为我们在常规链表中用来维持链表的 next 和 prev 指针都是指向对应类型的对象,因此一种数据结构的链表操作函数不能用于操作其 它数据结构的链表。为了解决这个问题,在 Linux 内核中采用了一种与类型无关的双向循环 链表实现方式,它的实现使得我们不用再为每个链表都要设计插入、查找、删除等相关的操 作函数。其实现方法就是将结构体中的指针 prev 和 next 从具体的数据结构中提取出来,构 成一种通用的双向循环链表数据结构 list_head。如果需要构造某类对象的特定链表,则只 需要在其结构体中定义一个类型为 list_head 类型的成员,通过这个定义的 list_head 类型的 成员将这类对象连接起来,形成所需的双向循环链表,进而通过通用链表函数对其进行操作。 显而易见是我们只需编写通用链表函数,就可构造和操作不同对象的链表,而无需为每个创 建的双向循环链表编写专用函数,从而大大的实现了代码的重用。 下面我们就真正的开始我们的 linux 内核双向循环链表之旅。读者可以从网上下载一个 linux 内核双向循环链表的list.h 的头文件,值得注意的就是因为内核版本的不同可能下载的头文 件有些差异,但是这个并不影响我们对于它的讲解。读者可以先看完全文后再动手也不迟, 用 list.h 头文件来实现我们的双向循环链表。为了便于讲解,我们就按照 list.h 头文件中代 码的先后顺序进行讲解。 补充一点:(注:如果读者看不懂下面这段代码,可以继续往下看,不会影响接下来的学习, 在接下来的部分还会有讲解,这部分代码是我写完全文后添加的,因为一开始我使用的是 #define list_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned long)(((type *)0)-member)))而不是#define list_entry(ptr, type, member) container_of(ptr, type, member)) [cpp] view plaincopy 1. #define container_of(ptr, type, member) ( { \ 2. const typeof( ((type *)0)-member ) *__mptr = (ptr); \ 3. (type *)( (char *)__mptr - offsetof(type,member) ); } ) 通过 typeof( ((type *)0)-member )得到 member 成员的类型,将指向 member 的指针 ptr 赋值给__mptr ,__mptr 指针的类型为 member 数据成员的类型。通过(char *)__mptr 将 __mptr

文档评论(0)

kehan123 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档