TAILQ ã®ã½ã¼ã¹ãèªãã§ C ã®ãã¤ã³ã¿ããã¹ã¿ã¼ããã
æ£æã¯ TAILQ ã®ã½ã¼ã¹ãèªãã§ãããæ®æ®µ C ãèªã¿æ¸ãããªãã®ã§ãã¨ã¦ãåå¼·ã«ãªã£ãããã¤ã³ã¿ã®ä½¿ãæ¹ãããã£ãï¼ãããªæ°æã¡ã«ãªããï¼ã
TAILQã£ã¦ï¼
TAILQ 㯠C ã®ãã¯ãã§æ¸ãããåæ¹åãªã³ã¯ãªã¹ãã®å®è£ ã
BSDãOSX ã glibc ã«å«ã¾ãã¦ããã
- http://freebsd.active-venture.com/FreeBSD-srctree/newsrc/sys/queue.h.html
- http://sourceware.org/git/?p=glibc.git;a=blob_plain;f=misc/sys/queue.h;hb=HEAD
åºæ¬çãªä½¿ãæ¹ã¯ä»¥ä¸ã®ãã¼ã¸ãåèã«ãªã£ãã
æ¬è¨äºã§ã¯ OSX ã®ã
- /usr/include/sys/queue.h
ãåç §ãããglibc ã®TAILQã§ãåºæ¬ã¯åãã
ãã¾ã
å ã 㯠C ã®åå¼·ã®ã¤ããã§ tmux ã®ã½ã¼ã¹ãè¦ã¦ãã¦ã使°ãªã queue.h ãéãã¦ãã¾ããããã
ä¾ãã°ãããªæãã
#define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
ããããæå³ãããããªãã
#define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ TRACEBUF \ }
ãªãã§nextã¨prevã§åãéãã®ããããããã³ã¡ã³ããä½ãè¨ãããã®ãããããªããåã®æ¬¡ã®è¦ç´ ã®ã¢ãã¬ã¹ï¼prevã¯åã®è¦ç´ ã§ã¯ãªãã®ãã
çµå±ãçè§£ã§ããã¨æããã¾ã§2æ¥ãããããã£ãã
ãªã¹ããä½ã£ã¦ã¢ãã¬ã¹ãåºåãããµã³ãã«
ãµã³ãã«
#include <stdio.h> #include <stdlib.h> #include <sys/queue.h> /* åæ¹åãªã³ã¯ãªã¹ã /usr/include/sys/queue.h ã® TAILQ ãçè§£ããããã®ã ãµã³ãã«ã§ãã */ /* ãªã¹ãè¦ç´ */ struct list_item { /* ãã¤ã³ã¿ãã©ããæãã¦ãããããããããããããã TAILQ_ENTRYã®åå¾ã«ã¡ã³ãã¼(num1,num2)ãå ¥ããã */ int num1; /* è¦ç´ ããªã³ã¯ããæ§é ä½ã tqe_nextã«æ¬¡ã®è¦ç´ ã®ã¢ãã¬ã¹ãè¨å®ãããã tqe_prevã«åã®è¦ç´ ã®tqe_nextã®ã¢ãã¬ã¹ãè¨å®ãããã */ TAILQ_ENTRY(list_item) links; /* ãã¤ã³ã¿ãã©ããæãã¦ãããããããããããããã TAILQ_ENTRYã®åå¾ã«ã¡ã³ãã¼(num1,num2)ãå ¥ããã */ int num2; }; /* ãªã¹ãã®æåã¨æå¾ã管çãããããæ§é ä½ã宣è¨ããã tqh_firstã«æåã®è¦ç´ ã®ã¢ãã¬ã¹ãè¨å®ãããã tqh_lastã«æå¾ã®è¦ç´ ã®tqe_nextãæãã¢ãã¬ã¹ãè¨å®ãããã */ TAILQ_HEAD(list_head, list_item); /* 渡ããããããã«è¦ç´ ã追å ããã */ void add_items(struct list_head *head) { int i = 0; struct list_item *item; for (i = 0; i < 3; i++) { item = (struct list_item*)malloc(sizeof(struct list_item)); item->num1 = i; item->num2 = 0; /* æ«å°¾ã«è¿½å ããã */ TAILQ_INSERT_TAIL(head, item, links); } } /* ãããã®ã¢ãã¬ã¹ãåºåããã */ void print_head(struct list_head *head) { printf("-- HEAD\n"); printf("%p: head\n", head); printf("%p: head->tqh_first = %p\n", &(head->tqh_first), head->tqh_first); printf("%p: head->tqh_last = %p\n", &(head->tqh_last), head->tqh_last); } /* ãªã¹ãã®åè¦ç´ ãåºåããã */ void print_items(struct list_head *head) { struct list_item *item; /* headãåç §ãããªã¹ããlinksã¡ã³ãã使ã£ã¦ã«ã¼ããããè¦ç´ ã¯itemã«å ¥ããã */ TAILQ_FOREACH(item, head, links) { printf("-- TAILQ_FOREACH %d\n", item->num1); /* itemã®ã¢ãã¬ã¹ */ printf("%p: item\n", item); printf("%p: item->num1 = %d\n", &(item->num1), item->num1); printf("%p: item->links.tqe_next = %p\n", &(item->links.tqe_next), item->links.tqe_next); printf("%p: item->links.tqe_prev = %p\n", &(item->links.tqe_prev), item->links.tqe_prev); printf("%p: item->num2 = %d\n", &(item->num2), item->num2); /* 以ä¸ãTAILQ_PREV ãã©ãããä»çµã¿ãªã®ã調ã¹ãããã®åºåã TAILQ_PREVã¯ãæå®ããè¦ç´ ã®1ã¤åã®è¦ç´ ãå¾ãããã®ãã¯ãã (*(((struct list_head *)(item->links.tqe_prev))->tqh_last)) ã®ããã«å±éãããã item->links.tqe_prev ãæãå ã list_headã¨è¦ãªã(struct list_head * ã«ãã£ã¹ã)ã æ§é ä½ã®2çªç®ã®ã¡ã³ã(tqh_last = tqe_prev)ãæãå ã«æ¸ããã ã¢ãã¬ã¹(tqe_next or tqh_last)ãã1ã¤åã®è¦ç´ ããæãã¦ããã ã2æ©æ»ã£ã¦1æ©é²ãã headã¾ã§ããã¨ãtqh_lastã«ãã£ã¦NULLãè¿ãã ã«ã¼ããæ£é ã§ãéé ã§ããæå¾ã®è¦ç´ ã®tqe_nextãçµäºæ¡ä»¶ã¨ãã¦æ©è½ãã¦ããã */ struct list_item **prev = item->links.tqe_prev; struct list_head *prev_head = (struct list_head *)prev; printf(" prev_head = %p\n", prev_head); printf(" prev_head->tqh_last = %p\n", prev_head->tqh_last); printf(" *prev_head->tqh_last = %p\n", *prev_head->tqh_last); } } /* ãªã¹ãç¨ã«ç¢ºä¿ããã¡ã¢ãªãè§£æ¾ããã */ void free_list(struct list_head *head) { printf("-- FREE\n"); /* è¦ç´ ãé ã«ãªã¹ãããå¤ãã¦è§£æ¾ */ struct list_item *item; while(!TAILQ_EMPTY(head)) { item = TAILQ_FIRST(head); printf("%p -> free\n", item); TAILQ_REMOVE(head, item, links); free(item); } /* ããããè§£æ¾ */ printf("%p -> free\n", head); free(head); } int main(int argc, char *argv[]) { /* mallocã使ã£ã¦ããªã¹ãã®è¦ç´ ã¨ã¢ãã¬ã¹ãæããã表示ãããããããããããã mallocã¯ãã¼ãã«ããã¼ã«ã«å¤æ°ã¯ã¹ã¿ãã¯ã«ä¿åãããã */ struct list_head *head = (struct list_head*)malloc(sizeof(struct list_head)); TAILQ_INIT(head); /* ãªã¹ã使 */ add_items(head); /* è¦ç´ 追å */ print_head(head); /* ãããåºå */ print_items(head); /* è¦ç´ åºå */ free_list(head); /* ã¡ã¢ãªè§£æ¾ */ return 0; }
ãããå®è¡ããã¨ã
$ gcc test.c $ ./a.out -- HEAD 0x100100080: head 0x100100080: head->tqh_first = 0x100100090 0x100100088: head->tqh_last = 0x1001000d8 -- TAILQ_FOREACH 0 0x100100090: item 0x100100090: item->num1 = 0 0x100100098: item->links.tqe_next = 0x1001000b0 0x1001000a0: item->links.tqe_prev = 0x100100080 0x1001000a8: item->num2 = 0 prev_head = 0x100100080 prev_head->tqh_last = 0x1001000d8 *prev_head->tqh_last = 0x0 -- TAILQ_FOREACH 1 0x1001000b0: item 0x1001000b0: item->num1 = 1 0x1001000b8: item->links.tqe_next = 0x1001000d0 0x1001000c0: item->links.tqe_prev = 0x100100098 0x1001000c8: item->num2 = 0 prev_head = 0x100100098 prev_head->tqh_last = 0x100100080 *prev_head->tqh_last = 0x100100090 -- TAILQ_FOREACH 2 0x1001000d0: item 0x1001000d0: item->num1 = 2 0x1001000d8: item->links.tqe_next = 0x0 0x1001000e0: item->links.tqe_prev = 0x1001000b8 0x1001000e8: item->num2 = 0 prev_head = 0x1001000b8 prev_head->tqh_last = 0x100100098 *prev_head->tqh_last = 0x1001000b0 -- FREE 0x100100090 -> free 0x1001000b0 -> free 0x1001000d0 -> free 0x100100080 -> free
ã®ããã«åºåãããã
å·¦å´ã®0x00000000: ããåæ§é ä½ã®ã¡ã³ããæ ¼ç´ããã¦ããã¢ãã¬ã¹ã8ãã¤ããã¤ã0x100100080 ã 0x1001000ef ã¾ã§ã使ã£ã¦ããã
num1ã¨num2ã¯ãªã¹ãè¦ç´ ã®ãã¼ã¿ããã¤ã³ã¿ãã©ããæãã¦ãããæç¢ºã«ããããããªã³ã¯(links)ã®åå¾ã«é ç½®ãã¦ããã
prev_* 㯠TAILQ_PREV ãã©ã®ããã«æ©è½ãã¦ããã調ã¹ãããã®åºåã
ãã¤ã³ã¿ã¯ããããä½ãæãã¦ãããã
ããã¾ããªã¤ã¡ã¼ã¸ã¯ã
ã®å³ããããããããå®éã«ã¯ããå°ãè¤éã«ã§ãã¦ãããä¸è¨ã®ãµã³ãã«ãå®è¡ããã¨ãè¦ç´ 3ã¤ã®ãªã¹ãã使ããã
ã®ããã«ãªã³ã¯ãããã
TAILQ_FIRST
ç°¡åãªã¨ãããããTAILQ_FIRSTã¯å é ã®è¦ç´ ãåå¾ããã
#define TAILQ_FIRST(head) ((head)->tqh_first)
headæ§é ä½ã®ã¡ã³ã tqh_first ã«ã¯ãªã¹ãå é è¦ç´ ã®ã¢ãã¬ã¹ãå ¥ã£ã¦ãããtqh_firstã®å®£è¨ã®ã¢ã¹ã¿ãªã¹ã¯(*)ã¯1åã* ã¯ããã®å structããæå³ããã
#define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ TRACEBUF \ }
ãã¤ã³ã¿ãæãã¦ããå ã®æ§é ä½ã®ã¡ã³ããåå¾ããã¨ãã¯ãã¢ãã¼æ¼ç®å(->)ã使ããã
TAILQ_NEXT
æå®ãããè¦ç´ (elm)ã®æ¬¡ã®è¦ç´ ãåå¾ãããã¯ãã
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
ãã¨ãã°ä¸ã®ãµã³ãã«ã³ã¼ãã ã¨ã ãã¯ã弿°ã®fieldã«ã¯linksãæå®ããã¦ã
(item)->links.tqe_next
ã¨å±éãããã
æå¾ã®è¦ç´ item2ã®tqe_nextã«ã¯NULLãè¨å®ããã¦ãããæå¾ã¾ã§ããã¨ãTAILQ_NEXTã¯NULLãè¿ãã
TAILQ_FOREACH
TAILQ_FIRSTã¨TAILQ_NEXTã使ãã¨ãæ£é ã®ã«ã¼ããã§ããã
#define TAILQ_FOREACH(var, head, field) \ for ((var) = TAILQ_FIRST((head)); \ (var); \ (var) = TAILQ_NEXT((var), field))
æå¾ã¾ã§ããã¨ãTAILQ_NEXTãNULLãè¿ããã«ã¼ããçµäºããã
TAILQ_PREV
PREVã¯ãNEXTããããã£ã¨è¤éã«ãªãã
#define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
以ä¸ã®å³ã¯item2ã®TAILQ_PREVãåå¾ããå ´åã
TAILQ_PREVããµã³ãã«ã³ã¼ãã®å¤æ°åã§å±éããã¨ã
(*(((struct head *)((item)->links.tqe_prev))->tqh_last))
ã¨ãªãããããåè§£ããã¨ã
struct list_item **prev = item->links.tqe_prev; struct list_head *prev_head = (struct list_head *)prev; *(prev_head->tqh_last)
ã«ãªãã
ã¾ããitem2ã®tqe_prevãåå¾ãããtqe_prev ã«ã¯ãitem1ã®tqe_nextã®ã¢ãã¬ã¹ãæ ¼ç´ããã¦ããã
次ã«ããã£ã¹ãã使ã£ã¦ item2 ã® tqe_prev ã list_head ãæãã¦ãããã®ã¨è¦ãªããitem1 ã® tqe_prev ã tqh_last ã¨å¼ã³æããã
item1ã® tqh_last (= tqe_prev) ã«ã¯ã item0 ã® tqe_next ã®ã¢ãã¬ã¹ãæ ¼ç´ããã¦ããã
æå¾ã«ãã¢ã¹ã¿ãªã¹ã¯ * ã§ item0 ã® tqe_next ã«æ ¼ç´ãããã¢ãã¬ã¹ãè¿ããããã§ item1 ã®å é ã®ã¢ãã¬ã¹ãå¾ãããã
item2ããitem1ãå¾ãããã«ã
- item2->links.tqe_prev
- item1->links.tqe_next
- item1->links.tqe_prev
- item0->links.tqe_next
ã¨è¾¿ã£ã¦ããã
ãã¤ã³ãï¼
- 2åæ»ã£ã¦1åé²ãã
- æ£ç¢ºã«ã¯2åæ»ã£ãå ã«æ¸ãããã¢ãã¬ã¹ãè¿ãã
- ã³ã¼ãä¸ã«ãå³ã®éç¢å°ã«ç¸å½ããæä½ã¯ãªãã
- C ã®ãã£ã¹ãã¯ããã¤ã³ã¿ãå¥ã®åãæãã¦ãããã¨ã«ã§ãã¦ãã¾ãã
- links ã®æ§é ä½ã«ã¯åå(ã¿ã°å)ã¯ã¤ãã¦ããªãã
- link_head ã¨åãããã¤ã³ã¿ã®2åã®çµãªã®ã§ãã£ã¹ããã¦ãå¹³æ°ã
- ポインタ虎の巻〜ポインタの型
char 4åã®é åãintã§ä¸æ°ã«åæåãã(è¯ããªã)ä¾ã
- struct list_item **tqe_prev;
- ãã¤ã³ã¿ã®ãã¤ã³ã¿ã
- ãèªåããã¤ã³ã¿ã次ããã¤ã³ã¿ãæ¬¡ã®æ¬¡ãstructãã
- tqe_prevã®æ¬¡ã®æ¬¡ã辿ãã¨èªè¦ç´ ã®å é ã«ãã©ãçãã
- /* address of previous next element */ ã¨ããã³ã¡ã³ãã¯ãpreviousã®tqe_nextã¡ã³ãã¨ããæå³ããã¡ãã£ã¨ã©ããã¨æãã
TAILQ_PREV å é è¦ç´ ã®å ´åã
item1 ã® TAILQ_PREV ãå¾ãå ´åã item2 ã¨å ¨ãåããã§ã¯ããªã¹ãã®å é item0 ã®åã®è¦ç´ ãå¾ããã¨ããã¨ã©ããªããã
tqh_lastã®å¼ã³æãã¯çºçããããã®ã¾ã¾æå¾ã®è¦ç´ item2 ã® tqe_next ã«é£ã¶ãtqe_nextã«ã¯NULLãã»ããããã¦ããã
ãã¤ã³ãï¼
- item2 ã®tqe_next ããTAILQ_NEXTã¨TAILQ_PREV両æ¹ã®æ«ç«¯ã示ãå¤ã¨ãã¦ä½¿ããã¦ããã
- ãªãããããã
TAILQ_LAST
æ«å°¾ã®è¦ç´ ãå¾ãã
#define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last) )->tqh_last))
TAILQ_PREV 㨠TAILQ_LAST ã¯ãã»ã¼ä¸ç·ãhead->tqh_lastã®prevã®nextã§ãªã¹ãæ«å°¾ã®å é ã¢ãã¬ã¹ãå¾ãã
TAILQ_INSERT_TAIL
ãªã¹ãã®æ´æ°å¦çã1ã¤ã ãè¦ã¦ã¿ãã
#define TAILQ_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); \ QMD_TRACE_HEAD(head); \ QMD_TRACE_ELEM(&(elm)->field); \ } while (0)
elmã追å ããè¦ç´ ã
do-while(0)ã¯ããã¯ãå±éã«ããã»ãã³ãã³ãåé¡ãèµ·ããã®ãé¿ããããã颿°å¼ã³åºãã®ããã«ä½¿ãããè¤æ°ã®æãããªããã¯ããæ¸ãããå ´å㯠do-while(0)ã§ã©ããããã
2è¡ç®ãelmã®tqe_nextãNULLã«è¨å®ããã
3è¡ç®ãelmã®tqe_prevãheadã®tqh_lastã«è¨å®ãããç¾å¨ã®æ«å°¾è¦ç´ ã®tqe_nextã®ã¢ãã¬ã¹ã
4è¡ç®ãããã¾ã§ã®æ«å°¾è¦ç´ ã® tqe_next ã«æ°ãã追å ããè¦ç´ ã®å
é ã¢ãã¬ã¹ãè¨å®ã
5è¡ç®ãheadã®tqh_lastããæ°è¦ç´ ã®tqe_nextã®ã¢ãã¬ã¹ã«è¨å®ã
æ®ã2è¡ã¯ãããã°ç¨ã
ãªã¹ãã空ã ã£ãå ´åã¯ãtqe_prev 㯠head ã® tqh_first ãæããheadã®åæåæã«tqh_lastãtqh_firstã®ã¢ãã¬ã¹ã«åæåããã¦ããã
#define TAILQ_INIT(head) do { \ TAILQ_FIRST((head)) = NULL; \ (head)->tqh_last = &TAILQ_FIRST((head)); \ QMD_TRACE_HEAD(head); \ } while (0) #define TAILQ_FIRST(head) ((head)->tqh_first)
gdb ã§å®è¡
ãµã³ãã«ããã°ã©ã ã gdb ã§å®è¡ãã¦ã¢ãã¬ã¹ã確èªãã¦ã¿ãã
$ gcc -g test.c $ gdb a.out # 132è¡ç®ããªã¹ããè§£æ¾ããåã«ãã¬ã¼ã¯ãã¤ã³ããè¨å®ã (gdb) break 132 # å®è¡ã (gdb) run # headã表示ã (gdb) p head $1 = (struct list_head *) 0x100100080 # headããtqh_firstã®ã¢ãã¬ã¹åå¾ã (gdb) p $1->tqh_first $2 = (struct list_item *) 0x100100090 # tqh_firstã®ä¸èº«ã§ããitem0ã表示ã (gdb) p *$2 $3 = { num1 = 0, links = { tqe_next = 0x1001000b0, tqe_prev = 0x100100080 }, num2 = 0 } # tqh_lastãlist_headãæãã¦ãããã®ã¨ãã¦åå¾ã (gdb) p (struct list_head *)head->tqh_last $4 = (struct list_head *) 0x1001000d8 # $4ãlist_headã¨ãã¦è¡¨ç¤ºã (gdb) p *$4 $5 = { tqh_first = 0x0, tqh_last = 0x1001000b8 } # item2ã®tqh_last (= tqe_prev)ã®å ã®å ããitem2èªèº«ã (gdb) p **($4->tqh_last) $6 = { num1 = 2, links = { tqe_next = 0x0, tqe_prev = 0x1001000b8 }, num2 = 0 } # æ®ããå®è¡ãã¦çµäºã (gdb) continue (gdb) quit