首页 > 编程知识 正文

tcpudp是哪层协议,seqstack是什么类型

时间:2023-05-05 11:03:06 阅读:19362 作者:4124

Tail queue位于/usr/include/x86 _ 64-Linux-GNU/sys/queue.h

queue.h包含以下数据结构:

双链表(List )单链表(单链尾队列(单链尾队列)单链尾队列(Tail queue )

头名

链表开头节点的名称为Tailq_head(headname,TYPE ); 定义

类型elm

用户定义必须使用Tailq_entry(type )的结构; 定义变量字段

头戴

头节点指针,即头名称*

字段

用TAILQ_ENTRY声明的变量名称

对于上面的demo,

头名是tailhead

类型elm是条目

头是tailhead*

字段为entries

Tail queue代码/* * tailqueuedeclarations.*/# definetailq _ head (name,type ) structname(structtype ) tqh _ fir sion/* addroflastnextelement *//} # definetailq _ head _ initializer (head ){ NULL,) head ).tqh _ first } # defifiniad/* addressofpreviousnextelement *//}/* * tailqueuefunctions.*/# definetailq _ empty (head ) )-tqh _ first=(var )=tailq_next () var (),field ) ) definetailq_foreach_reverse ) var,head,headname,field ) ) for (var (VAD (var )=Tailq_prev )、headname、field ) )、definetailq _ init (head ) do{Tailq_first ) ) head } (((}while(0) #definetailq_insert_after ) head,listelm,elm,field ) do(if ) ) t

AILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)TAILQ_NEXT((elm), field)->field.tqe_prev = &TAILQ_NEXT((elm), field);else(head)->tqh_last = &TAILQ_NEXT((elm), field);TAILQ_NEXT((listelm), field) = (elm);(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);} while (0)#defineTAILQ_INSERT_BEFORE(listelm, elm, field) do {(elm)->field.tqe_prev = (listelm)->field.tqe_prev;TAILQ_NEXT((elm), field) = (listelm);*(listelm)->field.tqe_prev = (elm);(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);} while (0)#defineTAILQ_INSERT_HEAD(head, elm, field) do {if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)TAILQ_FIRST((head))->field.tqe_prev = &TAILQ_NEXT((elm), field);else(head)->tqh_last = &TAILQ_NEXT((elm), field);TAILQ_FIRST((head)) = (elm);(elm)->field.tqe_prev = &TAILQ_FIRST((head));} while (0)#defineTAILQ_INSERT_TAIL(head, elm, field) do {TAILQ_NEXT((elm), field) = NULL;(elm)->field.tqe_prev = (head)->tqh_last;*(head)->tqh_last = (elm);(head)->tqh_last = &TAILQ_NEXT((elm), field);} while (0)#defineTAILQ_LAST(head, headname)(*(((struct headname *)((head)->tqh_last))->tqh_last))#defineTAILQ_NEXT(elm, field) ((elm)->field.tqe_next)#defineTAILQ_PREV(elm, headname, field)(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))#defineTAILQ_REMOVE(head, elm, field) do {if ((TAILQ_NEXT((elm), field)) != NULL)TAILQ_NEXT((elm), field)->field.tqe_prev = (elm)->field.tqe_prev;else(head)->tqh_last = (elm)->field.tqe_prev;*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);} while (0)

其中TAILQ_HEAD是头结点,TAILQ_ENTRY是非头结点

代码实现中比较难理解的是TAILQ_LAST和TAILQ_PREV。二级指针为啥要转一级指针,它又是如何得到尾元素和上一个元素的。

接下来通过一个demo来打印出Tail queue各个结点的地址和值。

#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <sys/queue.h>#define ITEM_NUM 4// #pragma pack(1)// 由于字节对齐,一共占用24字节typedef struct _QUEUE_ITEM { int value; TAILQ_ENTRY(_QUEUE_ITEM) entries;}QUEUE_ITEM;// #pragma pack()TAILQ_HEAD(TAIL_QUEUE, _QUEUE_ITEM) queue_head;int main(int argc, char **argv) { QUEUE_ITEM *item[ITEM_NUM]; TAILQ_INIT(&queue_head); int i = 0; for (i = 0; i < ITEM_NUM; ++i) { item[i] = (QUEUE_ITEM*)malloc(sizeof(QUEUE_ITEM)); item[i]->value = i; TAILQ_INSERT_TAIL(&queue_head, item[i], entries); } printf("queue_head:%p, first:%p, last:%pn", (void*)&queue_head, (void*)queue_head.tqh_first, (void*)queue_head.tqh_last); for(i = 0; i < ITEM_NUM; ++i) { printf("item[%d]: item:%p, next:%p, &next:%p, prev:%p, *prev:%pn", i, (void*)item[i], (void*)item[i]->entries.tqe_next, (void*)&(item[i]->entries.tqe_next), (void*)item[i]->entries.tqe_prev, (void*)(*item[i]->entries.tqe_prev)); } printf("last item:%pn", TAILQ_LAST(&queue_head, TAIL_QUEUE)); printf("sizeof(QUEUE_ITEM): %lun", sizeof(QUEUE_ITEM)); return 0;}

运行输出:

  通过上面输出可以得到Tail queue的内存布局如下:

粉红色的是域的地址,绿色是域值,0 1 2 3是data

注意上图标错了,entry指的tqe_next和tqe_prev,不包括data。

 现在再来看TAILQ_LAST

#defineTAILQ_LAST(head, headname)(*(((struct headname *)((head)->tqh_last))->tqh_last))

((head)->tqh_last)指向尾元素的tqe_next域的地址,即获取到尾元素的tqe_next域的地址0x1f35078

((struct headname *)((head)->tqh_last))将0x1f35078强转为头结点指针。为什么能强转呢?因为头结点和非头结点的内存布局是一样的(都是两个指针)。

(((struct headname *)((head)->tqh_last))->tqh_last)的意思是获取尾元素tqe_prev域的值0x1f35058,可以理解为0x1f35078+8后解引用。0x1f35058即倒数第二个结点的tqe_next域的地址。

 (*(((struct headname *)((head)->tqh_last))->tqh_last)) 最后对0x1f35058解引用,得到0x1f35070,即尾元素的首地址,此时拿到尾元素指针。

理解了TAILQ_LAST再看TAILQ_PREV就比较简单

#defineTAILQ_PREV(elm, headname, field)(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))

假设当前节点是节点2

((elm)->field.tqe_prev)拿到节点1的next域的地址0x1f35038

(((struct headname *)((elm)->field.tqe_prev))->tqh_last)拿到结点0的next域的地址0x1f35018

(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))对0x1f35018解引用得到节点1的首地址0x1f35030,即指向节点1的指针。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。