tailq中的TAILQ_FOREACH_REVERSE一些说明
这个东西之前就看过一次,看了半天才搞懂,结果今天看时又看不懂了,又折腾了好久才看清楚是咋回事。
最关键的就是(*(((struct headname *)((var)->field.tqe_prev))->tqh_last))),拆解开来就是:
1。((struct headname *)((var)->field.tqe_prev)) 这一步用于将上一个elm中的field结构中的tqe_next的地址取出来,其实也就是elm中field这个struct节点的地址(请注意到该struct中只有两个元素,而且该struct的结构与headname完全一致);
2。(@1->tqh_last) 这一步用于将上一个elm中的field中的第二个元素(即tqe_prev)的地址取出来,该地址就是上一个elm的上一个elm中的field的tqe_next的地址, 而该地址恰好指向的就是上一个elm的地址
3。(*@2) 这一步用于取出指向上一个elm的地址
呵呵,真tm够绕人的,其实在步骤1里面完全可以用elm中的field这个struct来进行强制类型转化,但是由于elm中的field这个struct是个定义在elm内部的而且没有名字的struct,因此无法显示的调用类似于(struct headname *)这样的强制类型转化,因此就只好用headname这个struct name来做这件事情了。
此外,**tqh_prev得到的其实是当前elm,*tqh_prev得到的是当前elm的指针,只有tqh_prev才能逃离当前elm的怪圈,指向上一个elm的field结构的第一个元素(也即整个field struct)的地址,紧接着从这里做文章又跳到了上一个elm的上一个elm的field struct里面,哈哈,够曲折的。
这个过程中,最精妙的莫过于那个强制类型转化了,其实本质上就是在从struct的第一个元素寻找第二个元素,其实完全可以用第一个元素的地址+4(32位系统,64位系统需要+8)就可以得到,但是这种做法可移植性太差,对于那种非pod的类型就不work了。
最关键的就是(*(((struct headname *)((var)->field.tqe_prev))->tqh_last))),拆解开来就是:
1。((struct headname *)((var)->field.tqe_prev)) 这一步用于将上一个elm中的field结构中的tqe_next的地址取出来,其实也就是elm中field这个struct节点的地址(请注意到该struct中只有两个元素,而且该struct的结构与headname完全一致);
2。(@1->tqh_last) 这一步用于将上一个elm中的field中的第二个元素(即tqe_prev)的地址取出来,该地址就是上一个elm的上一个elm中的field的tqe_next的地址, 而该地址恰好指向的就是上一个elm的地址
3。(*@2) 这一步用于取出指向上一个elm的地址
呵呵,真tm够绕人的,其实在步骤1里面完全可以用elm中的field这个struct来进行强制类型转化,但是由于elm中的field这个struct是个定义在elm内部的而且没有名字的struct,因此无法显示的调用类似于(struct headname *)这样的强制类型转化,因此就只好用headname这个struct name来做这件事情了。
此外,**tqh_prev得到的其实是当前elm,*tqh_prev得到的是当前elm的指针,只有tqh_prev才能逃离当前elm的怪圈,指向上一个elm的field结构的第一个元素(也即整个field struct)的地址,紧接着从这里做文章又跳到了上一个elm的上一个elm的field struct里面,哈哈,够曲折的。
这个过程中,最精妙的莫过于那个强制类型转化了,其实本质上就是在从struct的第一个元素寻找第二个元素,其实完全可以用第一个元素的地址+4(32位系统,64位系统需要+8)就可以得到,但是这种做法可移植性太差,对于那种非pod的类型就不work了。
本文深入解析了tailq中的TAILQ_FOREACH_REVERSE函数的工作原理,包括如何通过强制类型转换从一个元素找到另一个元素,以及如何在循环中高效地遍历链表。重点在于解释了关键步骤及其背后的逻辑,帮助读者更好地理解链表操作。
2458

被折叠的 条评论
为什么被折叠?



