当前位置:网站首页>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】
边栏推荐
- UEFI development learning 3 - create UEFI program
- Imx6ull bare metal development learning 1-assembly lit LED
- Connection mode - bridge and net
- Step motor generates S-curve upper computer
- Measurement fitting based on Halcon learning [III] PM_ measure_ board. Hdev routine
- 生产中影响滑环质量的因素
- Vofa+ software usage record
- Mlperf training v2.0 list released, with the same GPU configuration, the performance of Baidu PaddlePaddle ranks first in the world
- How to select conductive slip ring
- Makefile application
猜你喜欢
[trio basic tutorial 16 from introduction to proficiency] UDP communication test supplement
C # joint configuration with Halcon
H264 (I) i/p/b frame gop/idr/ and other parameters
Hardware 1 -- relationship between gain and magnification
[trio basic from introduction to mastery tutorial XIV] trio realizes unit axis multi-color code capture
Makefile application
Volatile of C language
Record the visual shock of the Winter Olympics and the introduction of the screen 2
Matlab2018b problem solving when installing embedded coder support package for stmicroelectronic
Shape template matching based on Halcon learning [vi] find_ mirror_ dies. Hdev routine
随机推荐
Software designer: 03 database system
Record the opening ceremony of Beijing Winter Olympics with display equipment
2021-10-28
General makefile (I) single C language compilation template
Shape template matching based on Halcon learning [viii] PM_ multiple_ models. Hdev routine
Nb-iot technical summary
Halcon's practice based on shape template matching [2]
Bootloader implementation of PIC MCU
Imx6ull bare metal development learning 2- use C language to light LED indicator
C WinForm [change the position of the form after running] - Practical Exercise 4
找不到实时聊天软件?给你推荐电商企业都在用的!
About yolov3, conduct map test directly
Embedded composition and route
Improve lighting C program
MLPerf Training v2.0 榜单发布,在同等GPU配置下百度飞桨性能世界第一
Baiwen 7-day smart home learning experience of Internet of things
WiFi wpa_ Detailed description of supplicant hostpad interface
UEFI development learning 6 - creation of protocol
Semiconductor devices (I) PN junction
Win10 shortcut key