sys/queue.h

概述

??????? sys/queue.h是LINUX/UNIX系統下面的一個標準頭文件,用一系列的數據結構定義了一隊列。包括singly-lined list, list, simple queue(Singly-linked Tail queue), tail queue, circle queue五種。

??????? 引用此頭文件對這五種數據結構的描述:

A singly-linked list is headed by a single forward pointer. The
elements are singly linked for minimum space and pointer manipulation
overhead at the expense of O(n) removal for arbitrary elements. New
elements can be added to the list after an existing element or at the
head of the list.? Elements being removed from the head of the list
should use the explicit macro for this purpose for optimum
efficiency. A singly-linked list may only be traversed in the forward
direction.? Singly-linked lists are ideal for applications with large
datasets and few or no removals or for implementing a LIFO queue.

A list is headed by a single forward pointer (or an array of forward
pointers for a hash table header). The elements are doubly linked
so that an arbitrary element can be removed without a need to
traverse the list. New elements can be added to the list before
or after an existing element or at the head of the list. A list
may only be traversed in the forward direction.

A simple queue is headed by a pair of pointers, one the head of the
list and the other to the tail of the list. The elements are singly
linked to save space, so elements can only be removed from the
head of the list. New elements can be added to the list after
an existing element, at the head of the list, or at the end of the
list. A simple queue may only be traversed in the forward direction.

A tail queue is headed by a pair of pointers, one to the head of the
list and the other to the tail of the list. The elements are doubly
linked so that an arbitrary element can be removed without a need to
traverse the list. New elements can be added to the list before or
after an existing element, at the head of the list, or at the end of
the list. A tail queue may be traversed in either direction.

A circle queue is headed by a pair of pointers, one to the head of the
list and the other to the tail of the list. The elements are doubly
linked so that an arbitrary element can be removed without a need to
traverse the list. New elements can be added to the list before or after
an existing element, at the head of the list, or at the end of the list.
A circle queue may be traversed in either direction, but has a more
complex end of list detection.

??????? 簡單來說,即是單鏈表,雙鏈表,單鏈隊列,雙向隊列(尾隊列)和雙向循環隊列。

??????? 雖然這是LINUX/UNIX里面的文件,但此文件本身沒有用到LINUX/UNIX的系統特性,因而可以跨平臺使用。queue.h下載。

??????? 下面對各數據結構簡單描述之。

單鏈表(singly-linked list)

??????? singly-linked list就是一單鏈表。

??????? singly-linked list相關的定義:

宏定義說明
SLIST_HEAD(name, type)定義表頭結點。
name: 表頭結點名。
type: 結點類型。
SLIST_HEAD_INITIALIZER(head)初始化頭結點。
head: 表頭結點。
SLIST_ENTRY(type)定義鏈表的鏈域。
type: 結點類型。

??????? singly-linked list函數:

宏定義說明
SLIST_INIT(head)初始化頭結點。
head: 表頭結點。
SLIST_INSERT_AFTER(slistelm, elm, field)將結點elm插入到結點slistelm后面。
slistelm:鏈表中某結點。
elm:要插入的結點。
field:鏈表中鏈域的名稱。
SLIST_INSERT_HEAD(head, elm, field)將結點elm插入到頭結點head后面。
head: 表頭結點。
elm:要插入的結點。
field:鏈表中鏈域的名稱。
SLIST_REMOVE_HEAD(head, field)移除將表頭結點下面一個結點。
head: 表頭結點。
field:鏈表中鏈域的名稱。
SLIST_REMOVE(head, elm, type, field)移除將elm結點,elm結點一定要是鏈表中一結點。
head: 表頭結點。
elm:某結點。
type: 結點類型。
field:鏈表中鏈域的名稱。
SLIST_FOREACH(var, head, field)遍歷鏈表,相當于for循環。
var: 結點類型的變量名稱。
head: 表頭結點。
field:鏈表中鏈域的名稱。

??????? singly-linked list 訪問方法:

宏定義說明
SLIST_EMPTY(head)判斷鏈表是否為空。
head: 表頭結點。
SLIST_FIRST(head)訪問鏈表里的第一個元素。
head: 表頭結點。
SLIST_NEXT(elm, field)訪問elm結點后一個元素。
elm:某結點。
field:鏈表中鏈域的名稱。

??????? 簡單例子:

struct SListItem
{int data;SLIST_ENTRY(SListItem) entry;
};
/*struct SListItem{int data;struct {struct SListItem* sle_next;} entry;}*/
void slist_demo()
{struct SListItem* item = NULL;SLIST_HEAD(SListHead, SListItem) shead;/*struct SListHead {struct SListItem* slh_first;} shead;*/SLIST_INIT(&shead);item = (struct SListItem*)malloc(sizeof(struct SListItem));item->data = 1;SLIST_INSERT_HEAD(&shead, item, entry);/*item->entry.sle_next = (&shead)->slh_first;(&shead)->slh_first = item;*/item = (struct SListItem*)malloc(sizeof(struct SListItem));item->data = 2;SLIST_INSERT_HEAD(&shead, item, entry);/*item->entry.sle_next = (&shead)->slh_first;(&shead)->slh_first = item;*/SLIST_FOREACH(item, &shead, entry){printf("%d ", item->data);}/*for(item = (&shead)->slh_first; item; item = item->entry.sle_next){...}*/printf("\n");while(!SLIST_EMPTY(&shead)){item = SLIST_FIRST(&shead);printf("remove %d\n", item->data);SLIST_REMOVE(&shead, item, SListItem, entry);free(item);}/*while(!((&shead)->slh_first == NULL)){item = (&shead)->slh_first;...(&shead)->slh_first = (&shead)->slh_first->entry.sle_next;...}*/
}
/*結果
2 1
remove 2
remove 1
*/

雙向鏈表(list)

??????? list就是雙向鏈表,不過鏈域有點古怪,指向前一個結點是指針的指針。

??????? list 相關定義

宏定義說明
LIST_HEAD(name, type)定義表頭結點。
name: 表頭結點名。
type: 結點類型。
LIST_HEAD_INITIALIZER(head)初始化頭結點。
head: 表頭結點。
LIST_ENTRY(type)定義鏈表的鏈域。
type: 結點類型。

??????? list函數

宏定義說明
LIST_INIT(head)初始化頭結點。
head: 表頭結點。
LIST_INSERT_AFTER(listelm, elm, field)將結點elm插入到結點listelm后面。
listelm:鏈表中某結點。
elm:要插入的結點。
field:鏈表中鏈域的名稱。
LIST_INSERT_BEFORE(listelm, elm, field)將結點elm插入到結點listelm前面。
listelm:鏈表中某結點。
elm:要插入的結點。
field:鏈表中鏈域的名稱。
LIST_INSERT_HEAD(head, elm, field)將結點elm插入到頭結點head后面。
head: 表頭結點。
elm:要插入的結點。
field:鏈表中鏈域的名稱。
LIST_REMOVE(elm, field)移除將elm結點。
elm:某結點。
field:鏈表中鏈域的名稱。
LIST_FOREACH(var, head, field)遍歷鏈表,相當于for循環。
var: 結點類型的變量名稱。
head: 表頭結點。
field:鏈表中鏈域的名稱。

??????? list訪問方法

宏定義說明
LIST_EMPTY(head)判斷鏈表是否為空。
head: 表頭結點。
LIST_FIRST(head)訪問鏈表里的第一個元素。
head: 表頭結點。
LIST_NEXT(elm, field)訪問elm結點后一個元素。
elm:某結點。
field:鏈表中鏈域的名稱。

??????? 注意,因為list是雙向鏈表,但在訪問方法里沒有寫出訪問前一個元素的宏。因而可以這樣寫一個,參數含義和LIST_NEXT一樣:

#define LIST_PRE(elm, field) \
(((elm)->field.le_pre) != &elm ? *((elm)->field.le_pre) : NULL)

??????? 簡單例子:

struct ListItem
{int data;LIST_ENTRY(ListItem) entry;
};
/*
struct ListItem
{int data;struct{struct ListItem* le_next;struct ListItem** le_prev;} entry;
};
*/
void list_demo()
{struct ListItem* item = NULL;LIST_HEAD(ListHead, ListItem) lhead;/*struct ListHead {struct ListItem* lh_first;} lhead;*/LIST_INIT(&lhead);/*do{(&lhead)->lh_first = NULL;}while(0);*/item = (struct ListItem*)malloc(sizeof(struct ListItem));item->data = 1;LIST_INSERT_HEAD(&lhead, item, entry);item = (struct ListItem*)malloc(sizeof(struct ListItem));item->data = 2;LIST_INSERT_HEAD(&lhead, item, entry);/*do{if(((item)->entry.le_next = (&lhead)->lh_first) != NULL)(&lhead)->lh_first->entry.le_pre = &(elm)->entry.le_next;(&lhead)->lh_first = (item);(item)->entry.le_prev = &(&lhead)->lh_first;}while(0);*/LIST_FOREACH(item, &lhead, entry){printf("%d ", item->data);}/*for ((item) = ((&lhead)->lh_first);(item);(item) = ((item)->entry.le_next)){...}    */printf("\n");while(!LIST_EMPTY(&lhead)){item = LIST_FIRST(&lhead);printf("remove %d\n", item->data);LIST_REMOVE(item, entry);free(item);}/*while(!((&lhead)->lh_first == NULL)){item = ((&lhead)->lh_first);...do{if ((item)->entry.le_next != NULL)                \(item)->entry.le_next->entry.le_prev =             \(item)->entry.le_prev;                \*(item)->entry.le_prev = (item)->entry.le_next;            \} while (0);...}*/
}
/*
結果
2 1
remove 2
remove 1
*/

簡單隊列(simple queue)

??????? 簡單來說,就是表對有兩個鏈域,分別指向頭和尾。

??????? simple queue 定義(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
SIMPLEQ_HEAD(name, type)?
SIMPLEQ_HEAD_INITIALIZER(head)?
SIMPLEQ_ENTRY(type)?

??????? simple queue函數(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
SIMPLEQ_INIT(head)?
SIMPLEQ_INSERT_HEAD(head, elm, field)?
SIMPLEQ_INSERT_TAIL(head, elm, field)?
SIMPLEQ_INSERT_AFTER(head, listelm, elm, field)?
SIMPLEQ_REMOVE_HEAD(head, field)?
SIMPLEQ_REMOVE(head, elm, type, field)?
SIMPLEQ_FOREACH(var, head, field)?

??????? simple queue方法(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
SIMPLEQ_EMPTY(head)?
SIMPLEQ_FIRST(head)?
SIMPLEQ_NEXT(elm, field)?

??????? 簡單例子:

??????? 用法與list用法類似,不再重復。

單鏈尾隊列(singled-linked tail queue)

??????? 這個和Simple queue是一樣的,參考simple queue

??????? singled-linked tail queue定義(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
STAILQ_HEAD(name, type)?
STAILQ_HEAD_INITIALIZER(head)?
STAILQ_ENTRY(type)?

?????? tail queue 函數(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
STAILQ_INIT(head)?
STAILQ_INSERT_HEAD(head, elm, field)?
STAILQ_INSERT_TAIL(head, elm, field)?
STAILQ_INSERT_AFTER(head, listelm, elm, field)?
STAILQ_REMOVE_HEAD(head, field)?
STAILQ_REMOVE(head, elm, type, field)?
STAILQ_FOREACH(var, head, field)?

??????? tail queue方法(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
STAILQ_EMPTY(head)?
STAILQ_FIRST(head)?
STAILQ_NEXT(elm, field)?

??????? 簡單例子:

??????? 用法與list用法類似,不再重復。

循環隊列(circle queue)

??????? 循環隊列。

??????? circle queue定義(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
LIST_HEAD(name, type)?
LIST_HEAD_INITIALIZER(head)?
LIST_ENTRY(type)?

??????? circle queue函數(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
LIST_INIT(head)?
LIST_INSERT_AFTER(listelm, elm, field)?
LIST_INSERT_BEFORE(listelm, elm, field)?
LIST_INSERT_HEAD(head, elm, field)?
LIST_REMOVE(elm, field)?
LIST_FOREACH(var, head, field)?

??????? circle queue訪問方法(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義說明
LIST_EMPTY(head)?
LIST_FIRST(head)?
LIST_NEXT(elm, field)?

??????? 簡單例子

??????? 用法與list用法類似,不再重復。

小結

??????? 雖然這是linux/unix實現的經過長時間考驗的成熟的數據結構,但是如果不是很熟悉的話,第一次用起來還是感覺挺不習慣的。但是好在各個數據結構的定義和方法都非常類似,接口比較統一,如果用多的了,熟悉了,感覺就不錯了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384933.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384933.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384933.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sys/queue.h分析(圖片復制不過來,查看原文)

這兩天有興趣學習使用了下系統頭文件sys/queue.h中的鏈表/隊列的實現,感覺實現的很是優美,關鍵是以后再也不需要自己實現這些基本的數據結構了,哈哈! 我的系統環境是 正好需要使用隊列,那么本篇就以其中的尾隊列&…

線程池原理及C語言實現線程池

備注:該線程池源碼參考自傳直播客培訓視頻配套資料; 源碼:https://pan.baidu.com/s/1zWuoE3q0KT5TUjmPKTb1lw 密碼:pp42 引言:線程池是一種多線程處理形式,大多用于高并發服務器上,它能合理有效…

iptables 的mangle表

mangle表的主要功能是根據規則修改數據包的一些標志位,以便其他規則或程序可以利用這種標志對數據包進行過濾或策略路由。 內網的客戶機通過Linux主機連入Internet,而Linux主機與Internet連接時有兩條線路,它們的網關如圖所示。現要求對內網進…

Linux常用命令(一)

history 查看歷史命令 ctrlp 向上翻歷史紀錄 ctrln 向下翻歷史紀錄 ctrlb 光標向左移動 ctrlf 光標向右移動 ctrla 光標移動到行首 ctrle 光標移動到行尾 ctrlh 刪除光標前一個 ctrld 刪除光標后一個 ctrlu 刪除光標前所有 ctrlL clear命令 清屏 tab鍵可以補全命令/填充路徑…

ip route / ip rule /iptables 配置策略路由

Linux 使用 ip route , ip rule , iptables 配置策略路由 要求192.168.0.100以內的使用 10.0.0.1 網關上網,其他IP使用 20.0.0.1 上網。 首先要在網關服務器上添加一個默認路由,當然這個指向是絕大多數的IP的出口網關。 ip route add default gw 20.0.0.…

iptables:tproxy做透明代理

什么是透明代理 客戶端向真實服務器發起連接,代理機冒充服務器與客戶端建立連接,并以客戶端ip與真實服務器建立連接進行代理轉發。因此對于客戶端與服務器來說,代理機都是透明的。 如何建立透明代理 本地socket捕獲數據包 nat方式 iptables…

編譯參數(-D)

程序中可以使用#ifdef來控制輸出信息 #include<stdio.h> #define DEBUGint main() {int a 10;int b 20;int sum a b; #ifdef DEBUGprintf("%d %d %d\n",a,b,sum); #endifreturn 0; } 這樣在有宏定義DEBGU的時候就會有信息輸出 如果注銷掉宏定義就不會有輸…

libpcap講解與API接口函數講解

ibpcap&#xff08;Packet Capture Library&#xff09;&#xff0c;即數據包捕獲函數庫&#xff0c;是Unix/Linux平臺下的網絡數據包捕獲函數庫。它是一個獨立于系統的用戶層包捕獲的API接口&#xff0c;為底層網絡監測提供了一個可移植的框架。 一、libpcap工作原理 libpcap…

Linux常用命令(三)

man 查看幫助文檔 alias ls : 查看命令是否被封裝 echo &#xff1a; 顯示字符串到屏幕終端 echo $PATH : 將環境變量打印出來 poweroff&#xff1a;關機 rebot&#xff1a;重啟 需要管理員權限 vim是從vi發展過來的文本編輯器 命令模式&#xff1a;打開文件之后默認進入命令模…

淺談iptables防SYN Flood攻擊和CC攻擊

何為syn flood攻擊&#xff1a; SYN Flood是一種廣為人知的DoS&#xff08;拒絕服務攻擊&#xff09;是DDoS&#xff08;分布式拒絕服務攻擊&#xff09;的方式之一&#xff0c;這是一種利用TCP協議缺陷&#xff0c;發送大量偽造的TCP連接請求&#xff0c;從而使得被攻擊方資源…

Linux之靜態庫

命名規則&#xff1a; lib 庫的名字 .a 制作步驟 生成對應.o文件 .c .o 將生成的.o文件打包 ar rcs 靜態庫的名字&#xff08;libMytest.a&#xff09; 生成的所有的.o 發布和使用靜態庫&#xff1a; 1&#xff09; 發布靜態 2&#xff09; 頭文件 文件如下圖所示&…

iptables詳解和練習

防火墻&#xff0c;其實說白了講&#xff0c;就是用于實現Linux下訪問控制的功能的&#xff0c;它分為硬件的或者軟件的防火墻兩種。無論是在哪個網絡中&#xff0c;防火墻工作的地方一定是在網絡的邊緣。而我們的任務就是需要去定義到底防火墻如何工作&#xff0c;這就是防火墻…

Linux之動態庫

命令規則 lib 名字 .so 制作步驟 1&#xff09;生成與位置無關的代碼&#xff08;生成與位置無關的代碼&#xff09; 2&#xff09;將.o打包成共享庫&#xff08;動態庫&#xff09; 發布和使用共享庫 動態庫運行原理&#xff1a; 生成動態庫&#xff1a; gcc -fPIC -c *.c -…

linux下源碼安裝vsftpd-3.0.2

1&#xff09;在http://vsftpd.beasts.org/網站中查找并下載 vsftpd-3.0.2.tar.gz源碼包 2)如果自己的機器上安裝有yum可以用yum grouplist | less指令查看以下開發環境&#xff0c;當然這一步不做也行 3&#xff09;拆解源碼包 4&#xff09;查看源碼包 5&#xff09;編輯…

Linux之GDB調試命令

gdb啟動 gdb 程序名 l 查看源代碼&#xff08;默認顯示十行&#xff09; l 文件名&#xff1a;行數 l 文件名&#xff1a;函數名 添加斷點 break 行數 &#xff08;b 也行&#xff09; b 15 if i 15 條件斷點 i b 查看斷點信息 start 程序執行一步 n 單步調試 s 單步&#xf…

Gdb 調試core文件詳解

一&#xff0c;什么是coredump 我們經常聽到大家說到程序core掉了&#xff0c;需要定位解決&#xff0c;這里說的大部分是指對應程序由于各種異常或者bug導致在運行過程中異常退出或者中止&#xff0c;并且在滿足一定條件下&#xff08;這里為什么說需要滿足一定的條件呢&#…

Linux之GDB命令(二)

gdb命令&#xff1a; 前提條件&#xff1a;可執行文件必須包含調試信息 gcc -ggdb 文件名 –啟動gdb調試查看代碼命令 當前文件&#xff1a; list 行號&#xff08;函數名&#xff09; 指定文件&#xff1a; list 文件名&#xff1a;行號&#xff08;函數名&#x…

Windows下編譯openssl庫

1、概述 OpenSSL是一個開放源代碼的軟件庫包&#xff0c;它實現了 SSL&#xff08;Secure SocketLayer&#xff09;和 TLS&#xff08;Transport Layer Security&#xff09;協議&#xff0c;所以應用程序可以使用這個包來進行安全通信&#xff0c;避免竊聽&#xff0c;同時確…

Makefile規則介紹

Makefile 一個規則 三要素&#xff1a;目標&#xff0c;依賴&#xff0c;命令 目標&#xff1a;依賴命令 1、第一條規則是用來生成終極目標的規則 如果規則中的依賴不存在&#xff0c;向下尋找其他的規則 更新機制&#xff1a;比較的是目標文件和依賴文件的時間 兩個函…

windows環境下C語言socket編程

最近由于實驗需要&#xff0c;要求寫一個c程序與java程序通信的軟件&#xff0c;為了測試首先寫了一個windows環境下c語言的socket&#xff08;tcp&#xff09;通信程序。 首先socket通信的步驟&#xff1a; 圖一 socket通信步驟&#xff08;轉載) 圖二 三次握手協議&…