当前位置:网站首页>Stablq of linked list
Stablq of linked list
2022-07-05 08:06:00 【Car chezi】
List of articles
STAILQ Sketch Map
STAILQ and LIST The difference is that the ,head There's a pointer inside stqh_last, Pointing to the last node stqe_next
Be careful : Some places also put STAILQ It's called simple queue, Change the interface prefix to SIMPLEQ_
Interface and implementation
Post the code first .( Be careful : Different versions of code may be different )
/* * Singly-linked Tail queue declarations. */
#define STAILQ_HEAD(name, type) \ struct name {
\ struct type *stqh_first;/* first element */ \ struct type **stqh_last;/* addr of last next element */ \ }
#define STAILQ_HEAD_INITIALIZER(head) \ {
NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \ struct {
\ struct type *stqe_next; /* next element */ \ }
/* * Singly-linked Tail queue functions. */
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \ for((var) = STAILQ_FIRST((head)); \ (var); \ (var) = STAILQ_NEXT((var), field))
#define STAILQ_INIT(head) do {
\ STAILQ_FIRST((head)) = NULL; \ (head)->stqh_last = &STAILQ_FIRST((head)); \ } while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {
\ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ STAILQ_NEXT((tqelm), field) = (elm); \ } while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do {
\ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ STAILQ_FIRST((head)) = (elm); \ } while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do {
\ STAILQ_NEXT((elm), field) = NULL; \ *(head)->stqh_last = (elm); \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ } while (0)
#define STAILQ_LAST(head, type, field) \ (STAILQ_EMPTY(head) ? \ NULL : \ ((struct type *) \ ((char *)((head)->stqh_last) - offsetof(struct type, field))))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do {
\ if (STAILQ_FIRST((head)) == (elm)) {
\ STAILQ_REMOVE_HEAD(head, field); \ } \ else {
\ struct type *curelm = STAILQ_FIRST((head)); \ while (STAILQ_NEXT(curelm, field) != (elm)) \ curelm = STAILQ_NEXT(curelm, field); \ if ((STAILQ_NEXT(curelm, field) = \ STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ } \ } while (0)
#define STAILQ_REMOVE_HEAD(head, field) do {
\ if ((STAILQ_FIRST((head)) = \ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ (head)->stqh_last = &STAILQ_FIRST((head)); \ } while (0)
#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do {
\ if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ (head)->stqh_last = &STAILQ_FIRST((head)); \ } while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do {
\ if ((STAILQ_NEXT(elm, field) = \ STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ } while (0)
give an example
Let's take an example , Examples come from :https://manpages.courier-mta.org/htmlman3/stailq.3.html
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/queue.h>
struct entry {
int data;
STAILQ_ENTRY(entry) entries; /* Singly linked tail queue */
};
STAILQ_HEAD(stailhead, entry);
int
main(void)
{
struct entry *n1, *n2, *n3, *np;
struct stailhead head; /* Singly linked tail queue head */
STAILQ_INIT(&head); /* Initialize the queue */
n1 = malloc(sizeof(struct entry)); /* Insert at the head */
STAILQ_INSERT_HEAD(&head, n1, entries);
n1 = malloc(sizeof(struct entry)); /* Insert at the tail */
STAILQ_INSERT_TAIL(&head, n1, entries);
n2 = malloc(sizeof(struct entry)); /* Insert after */
STAILQ_INSERT_AFTER(&head, n1, n2, entries);
STAILQ_REMOVE(&head, n2, entry, entries); /* Deletion */
free(n2);
n3 = STAILQ_FIRST(&head);
STAILQ_REMOVE_HEAD(&head, entries); /* Deletion from the head */
free(n3);
n1 = STAILQ_FIRST(&head);
n1->data = 0;
for (int i = 1; i < 5; i++) {
n1 = malloc(sizeof(struct entry));
STAILQ_INSERT_HEAD(&head, n1, entries);
n1->data = i;
}
/* Forward traversal */
STAILQ_FOREACH(np, &head, entries)
printf("%i\n", np->data);
/* TailQ deletion */
n1 = STAILQ_FIRST(&head);
while (n1 != NULL) {
n2 = STAILQ_NEXT(n1, entries);
free(n1);
n1 = n2;
}
STAILQ_INIT(&head);
exit(EXIT_SUCCESS);
}
The code analysis
STAILQ_ENTRY and STAILQ_HEAD
struct entry {
int data;
STAILQ_ENTRY(entry) entries; /* Singly linked tail queue */
};
STAILQ_HEAD(stailhead, entry);
The macro is replaced by
struct entry {
int data;
struct {
struct entry *stqe_next;
} entries;
};
struct stailhead {
struct entry *stqh_first;
struct entry **stqh_last;
};
Actually sum SLIST almost , The only difference is 10 That's ok , There is an extra pointer to the tail node ( To be exact, it points to the tail node stqe_next)
STAILQ_INIT and STAILQ_INSERT_HEAD
struct entry *n1, *n2, *n3, *np;
struct stailhead head; /* Singly linked tail queue head */
STAILQ_INIT(&head); /* Initialize the queue */
n1 = malloc(sizeof(struct entry)); /* Insert at the head */
STAILQ_INSERT_HEAD(&head, n1, entries);
5: Macro expansion yes
(&head)->stqh_first = ((void *)0);
(&head)->stqh_last = &(&head)->stqh_first;
The initialization of the linked list is empty ,stqh_first be equal to NULL,stqh_last self-directed stqh_first
8: Macro expansion yes
if (((n1)->entries.stqe_next = (&head)->stqh_first) == ((void *)0))
(&head)->stqh_last = &(n1)->entries.stqe_next;
(&head)->stqh_first = (n1);
hold n1 Insert the first position of the linked list , Which pointer value will be affected ?
- stqh_first
- n1 Of stqe_next
- If the list is empty , So insert n1 after ,stqh_last Change, too
The first 1 OK, it's solved 2
The first 2 OK, it's solved 3
The first 3 OK, it's solved 1
STAILQ_INSERT_TAIL
n1 = malloc(sizeof(struct entry)); /* Insert at the tail */
STAILQ_INSERT_TAIL(&head, n1, entries);
2: Macro replacement is
(n1)->entries.stqe_next = ((void *)0);
*(&head)->stqh_last = (n1);
(&head)->stqh_last = &(n1)->entries.stqe_next;
hold n1 Insert the last position of the linked list , Which pointer values will be affected ?
- stqh_last
- n1 Of stqe_next, Need to be for NULL
- The original last node ( The assumption is n8) Of stqe_next
The first 1 OK, it's solved 2
The first 2 OK, a little trouble ,(&head)->stqh_last Point to n8 Node stqe_next,*(&head)->stqh_last Namely n8 Node stqe_next, assignment n1 Give it , It's solved 3
The first 3 OK, it's solved 1
STAILQ_INSERT_AFTER
n2 = malloc(sizeof(struct entry)); /* Insert after */
STAILQ_INSERT_AFTER(&head, n1, n2, entries);
The first 2 OK means to put n2 Insert into n1 Behind
After the code is expanded
if (((n2)->entries.stqe_next = (n1)->entries.stqe_next) == ((void *)0))
(&head)->stqh_last = &(n2)->entries.stqe_next;
(n1)->entries.stqe_next = (n2);
hold n2 Insert into n1 Behind , Which pointer values will be affected ?
- n1 Of stqe_next
- n2 Of stqe_next
- If n2 It's the last node , Still have to amend (&head)->stqh_last
The first 1 Yes (n2)->entries.stqe_next = (n1)->entries.stqe_next)
It's solved 2
The first 3 OK, it's solved 1
The first 2 OK, it's solved 3
STAILQ_REMOVE
STAILQ_REMOVE(&head, n2, entry, entries); /* Deletion */
free(n2);
The first 1 Row expansion yes , A little longer
if ((&head)->stqh_first == (n2)) {
if ((((&head))->stqh_first = ((&head))->stqh_first->entries.stqe_next) == ((void *)0))
((&head))->stqh_last = &((&head))->stqh_first;
} else {
struct entry *curelm = (&head)->stqh_first;
while (curelm->entries.stqe_next != (n2))
curelm = curelm->entries.stqe_next;
if ((curelm->entries.stqe_next = curelm->entries.stqe_next->entries.stqe_next) == ((void *)0))
(&head)->stqh_last = &(curelm)->entries.stqe_next;
}
branch 2 In this case .n2 Is it the first node ( The first 1 Line code ), If it is , The pointers that need to be modified are
- (&head)->stqh_first
- If n2 Is the only node , Then you need to modify (&head))->stqh_last
The first 2 The first half of the line solves 1
The first 3 OK, it's solved 2
If n2 Not the first node , Then perform 5-10, To find the first n2 (6-7 That's ok ), When it's found , curelm representative n2 The front node . The pointers that need to be modified at this time are :
- curelm Of stqe_next
- If n2 It's the last node , It needs to be modified after deletion (&head))->stqh_last
The first 8 The first half of the line solves 1
The first 9 OK, it's solved 2
STAILQ_FIRST and STAILQ_REMOVE_HEAD
n3 = STAILQ_FIRST(&head);
STAILQ_REMOVE_HEAD(&head, entries); /* Deletion from the head */
free(n3);
STAILQ_FIRST Relatively simple , Is to get the first node of the linked list , Be careful , Not delete
The first 1 OK, expand :n3 = ((&head)->stqh_first);
STAILQ_REMOVE_HEAD Is to delete the first node
The first 2 OK, expand :
if (((&head)->stqh_first = (&head)->stqh_first->entries.stqe_next) == ((void *)0))
(&head)->stqh_last = &(&head)->stqh_first;
If before deletion , Only one node , Then it needs to be modified stqh_last, That is the first. 2 That's ok
If you have multiple nodes , Then just modify stqh_first( The first 1 The first half of the line )
STAILQ_FOREACH
/* Forward traversal */
STAILQ_FOREACH(np, &head, entries)
printf("%i\n", np->data);
STAILQ_FOREACH(np, &head, entries) Used to traverse each node of the linked list . The first parameter is a temporary variable , Point to the current node , The second parameter is the address of the header , Third entries Is the member name of the unlabeled structure .
The first 2 OK, expand :
for ((np) = ((&head)->stqh_first); (np); (np) = ((np)->entries.stqe_next))
printf("%i\n", np->data);
Typical traversal . Be careful , This traversal cannot be deleted , Because if you put np The node pointed to is deleted ,
(np)->entries.stqe_next
This sentence is wrong .
STAILQ_NEXT
/* TailQ deletion */
n1 = STAILQ_FIRST(&head);
while (n1 != NULL) {
n2 = STAILQ_NEXT(n1, entries);
free(n1);
n1 = n2;
}
STAILQ_NEXT(n1, entries) It means take n1 The next node of
The first 4 Row expansion yes n2 = ((n1)->entries.stqe_next);
Relatively simple .
This code also shows how to delete the entire linked list .
How many macros are there , There is no use in the example , Let's have a look .
STAILQ_EMPTY
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
It's easy to understand , No explanation. .
STAILQ_LAST
#define STAILQ_LAST(head, type, field) \ (STAILQ_EMPTY(head) ? \ NULL : \ ((struct type *) \ ((char *)((head)->stqh_last) - offsetof(struct type, field))))
Be careful , my Linux On the operating system , This macro is not included , therefore , If you want to use , You need to include this code manually .
The meaning of this macro is to find the last node of the queue . It works like this :
n1 = STAILQ_LAST(&head, entry, entries);
At the beginning of this article , Yes
struct entry {
int data;
STAILQ_ENTRY(entry) entries; /* Singly linked tail queue */
};
STAILQ_HEAD(stailhead, entry);
n1 = STAILQ_LAST(&head, entry, entries)
The last two parameters of should correspond to 3 Definition of line .
Let's look back STAILQ_LAST Code for
#define STAILQ_LAST(head, type, field) \ (STAILQ_EMPTY(head) ? \ NULL : \ ((struct type *) \ ((char *)((head)->stqh_last) - offsetof(struct type, field))))
If the list is empty , Just go back to NULL, What if it is not empty ? Of course, follow (head)->stqh_last Find the right last node .
The problem is ,(head)->stqh_last It points to the last node entries.stqe_next Domain
struct entry {
int data;
struct {
struct entry *stqe_next;
} entries;
};
That is the first. 4 That's ok ,(head)->stqh_last The value of is struct entry *stqe_next The address of , instead of struct entry The address of , So we need to change . Conversion needs to use
offsetof(struct type, field)
This is also a macro , The code is probably /usr/src/linux-headers-4.8.0-36-generic/include/linux/stddef.h
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
there TYPE Represents a structure type ,MEMBER Represents a member in the structure , This macro calculates the position offset of the member in the structure ( In bytes )
Suppose a structural variable ( The type is struct entry) The starting address of is 0x1234, One of its members is data, Excuse me, data What is the address of the variable ?
You can ask :
&((struct entry *)0x1234)->data
->
Higher priority than type conversion , So we need to add parentheses .((struct entry *)0x1234)->data
You get members , Take the address again , Get the address of the member , Another type conversion , Turn to unsigned integer :
(size_t)&((struct entry *)0x1234)->data
Finally get the starting address of the member , At this time, let's look at its offset from the starting address of the structure variable ? That is, subtract the address of the structure variable from the address of the member :
(size_t)&((struct entry *)0x1234)->data - 0x1234
It's not hard to see. , there 0x1234 You can change it into any number , Because the offset is a relative quantity , It has nothing to do with the starting address
For simplicity , Then put 0x1234 Switch to 0 Well .
We do general treatment , hold struct entry It's called TYPE, hold data It's called MEMBER, So there it is
((size_t)&((TYPE *)0)->MEMBER)
Let's get back to the point ,(head)->stqh_last The value of is struct entry *stqe_next The address of , instead of struct entry The address of ,* If we knew struct entry stqe_next be relative to struct entry The migration x, Then use (head)->stqh_last subtract x That's all right. .
utilize offsetof(struct type, field)
To find the offset , At the same time, notice struct entry *stqe_next and entries It's the same address , So the offset is :offsetof(struct entry , entries )
The address of the last node is :
(struct entry *)((char*)((head)->stqh_last) - offsetof(struct entry, entries)))
Generalize the above formula ,entry Switch to type,entries Switch to field, You get the :
((struct type *) \
((char *)((head)->stqh_last) - offsetof(struct type, field))))
There's actually a simpler way , Directly use the container_of
macro , Here is just a hint , I'm not going to expand it .
【end】
边栏推荐
- Imx6ull bare metal development learning 2- use C language to light LED indicator
- UEFI development learning 2 - running ovmf in QEMU
- Win10 shortcut key
- C # joint configuration with Halcon
- About yolov3, conduct map test directly
- PMSM dead time compensation
- 【云原生 | 从零开始学Kubernetes】三、Kubernetes集群管理工具kubectl
- Drive LED -- GPIO control
- 研究發現,跨境電商客服系統都有這五點功能!
- C WinForm [help interface - send email] - practice five
猜你喜欢
Basic embedded concepts
1-stm32 operation environment construction
The research found that the cross-border e-commerce customer service system has these five functions!
C # joint configuration with Halcon
PMSM dead time compensation
Programming knowledge -- basis of C language
My-basic application 2: my-basic installation and operation
Shape template matching based on Halcon learning [v] find_ cocoa_ packages_ max_ deformation. Hdev routine
[untitled] record the visual shock of the Winter Olympics and the introduction of the display screen
[tutorial 19 of trio basic from introduction to proficiency] detailed introduction of trio as a slave station connecting to the third-party bus (anybus PROFIBUS DP...)
随机推荐
MLPerf Training v2.0 榜单发布,在同等GPU配置下百度飞桨性能世界第一
MySQL blind note common functions
Summary -st2.0 Hall angle estimation
Vofa+ software usage record
How to select conductive slip ring
Programming knowledge -- assembly knowledge
Step motor generates S-curve upper computer
. Net service governance flow limiting middleware -fireflysoft RateLimit
LED display equipment records of the opening ceremony of the Beijing Winter Olympics
Factors affecting the quality of slip rings in production
Correlation based template matching based on Halcon learning [II] find_ ncc_ model_ defocused_ precision. hdev
Hardware 1 -- relationship between gain and magnification
Altium designer 19.1.18 - change the transparency of copper laying
[trio basic from introduction to mastery tutorial XIV] trio realizes unit axis multi-color code capture
Measurement fitting based on Halcon learning [i] fuse Hdev routine
生产中影响滑环质量的因素
Shell script basic syntax
Altium designer learning (I)
找不到实时聊天软件?给你推荐电商企业都在用的!
Explain task scheduling based on Cortex-M3 in detail (Part 1)