当前位置:网站首页>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】
边栏推荐
- Live555 RTSP audio and video streaming summary (II) modify RTSP server streaming URL address
- Global and Chinese market of rammers 2022-2028: Research Report on technology, participants, trends, market size and share
- Measurement fitting based on Halcon learning [III] PM_ measure_ board. Hdev routine
- C # joint configuration with Halcon
- Record the opening ceremony of Beijing Winter Olympics with display equipment
- Soem EtherCAT source code analysis attachment 1 (establishment of communication operation environment)
- VESC Benjamin test motor parameters
- Basic information commands and functions of kernel development
- How to excavate and research ideas from the paper
- Management and use of DokuWiki
猜你喜欢
C WinForm [exit application] - practice 3
Measurement fitting based on Halcon learning [i] fuse Hdev routine
Reasons for rapid wear of conductive slip rings
How to migrate the device data accessed by the RTSP of the easycvr platform to easynvr?
Introduction of air gap, etc
[trio basic tutorial 16 from introduction to proficiency] UDP communication test supplement
[trio basic tutorial 18 from introduction to proficiency] trio motion controller UDP fast exchange data communication
Embedded composition and route
MySQL blind note common functions
Markdown tips
随机推荐
Interview catalogue
2021-10-28
1089 insert or merge, including test point 5
UEFI development learning 6 - creation of protocol
Extern keyword function
Verilog -- state machine coding method
Drive LED -- GPIO control
Record the torch encountered by win10 cuda. is_ False problem in available()
Shape template matching based on Halcon learning [9] PM_ multiple_ dxf_ models. Hdev routine -- [read and write XLD from DXF file]
Solutions to compilation warnings in Quartus II
[professional literacy] specific direction of analog integrated circuits
Shape template matching based on Halcon learning [vi] find_ mirror_ dies. Hdev routine
Global and Chinese markets of large aperture scintillators 2022-2028: Research Report on technology, participants, trends, market size and share
C # joint configuration with Halcon
L'étude a révélé que le système de service à la clientèle du commerce électronique transfrontalier a ces cinq fonctions!
Correlation based template matching based on Halcon learning [II] find_ ncc_ model_ defocused_ precision. hdev
C WinForm [help interface - send email] - practice five
Semiconductor devices (III) FET
Altium designer 19.1.18 - clear information generated by measuring distance
Process communication mode between different hosts -- socket