# nginx数据结构_循环链表

# 主要思想:

链表中不存数据域

只定义循环链表的常见操作

链表节点作为数据结构体中的一个最后一个字段,起到串联数据的作用

使用linux的一个内核宏

offsetof(type, link)
获取type结构体中link字段的偏移量,相对于type开始的位置
比如ngx_qtest_t类型 offsetof(ngx_qtest_t, link) 的值应该是int 4字节 + name 32字节 = 36
1
2
3

# queue.h文件


/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */



#ifndef _NGX_QUEUE_H_INCLUDED_
#define _NGX_QUEUE_H_INCLUDED_


#define u_char char
#define ngx_int_t int

typedef struct ngx_queue_s  ngx_queue_t;

struct ngx_queue_s {
    ngx_queue_t  *prev;
    ngx_queue_t  *next;
};


#define ngx_queue_init(q)                                                     \
    (q)->prev = q;                                                            \
    (q)->next = q


#define ngx_queue_empty(h)                                                    \
    (h == (h)->prev)


#define ngx_queue_insert_head(h, x)                                           \
    (x)->next = (h)->next;                                                    \
    (x)->next->prev = x;                                                      \
    (x)->prev = h;                                                            \
    (h)->next = x


#define ngx_queue_insert_after   ngx_queue_insert_head


#define ngx_queue_insert_tail(h, x)                                           \
    (x)->prev = (h)->prev;                                                    \
    (x)->prev->next = x;                                                      \
    (x)->next = h;                                                            \
    (h)->prev = x


#define ngx_queue_head(h)                                                     \
    (h)->next


#define ngx_queue_last(h)                                                     \
    (h)->prev


#define ngx_queue_sentinel(h)                                                 \
    (h)


#define ngx_queue_next(q)                                                     \
    (q)->next


#define ngx_queue_prev(q)                                                     \
    (q)->prev


#if (NGX_DEBUG)

#define ngx_queue_remove(x)                                                   \
    (x)->next->prev = (x)->prev;                                              \
    (x)->prev->next = (x)->next;                                              \
    (x)->prev = NULL;                                                         \
    (x)->next = NULL

#else

#define ngx_queue_remove(x)                                                   \
    (x)->next->prev = (x)->prev;                                              \
    (x)->prev->next = (x)->next

#endif


#define ngx_queue_split(h, q, n)                                              \
    (n)->prev = (h)->prev;                                                    \
    (n)->prev->next = n;                                                      \
    (n)->next = q;                                                            \
    (h)->prev = (q)->prev;                                                    \
    (h)->prev->next = h;                                                      \
    (q)->prev = n;


#define ngx_queue_add(h, n)                                                   \
    (h)->prev->next = (n)->next;                                              \
    (n)->next->prev = (h)->prev;                                              \
    (h)->prev = (n)->prev;                                                    \
    (h)->prev->next = h;


#define ngx_queue_data(q, type, link)                                         \
    (type *) ((u_char *) q - offsetof(type, link))


#endif /* _NGX_QUEUE_H_INCLUDED_ */

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

# main.c

#include<stdio.h>
#include"queue.h"
#pragma pack(1)  // 规定对其字节数 , gcc 64位默认是pack(8) 

#define offsetof(TYPE, MEMBER)   ((size_t)&((TYPE *)0)->MEMBER)
// 将0地址开始内存映射为结构体TYPE, 然后取MEMBER字段的地址,这个地址就是MEMBER相对于结构体开始的偏移量。
// 再转为int64类型size_t 
  
typedef struct  {

	int key;
    char name[32];
	ngx_queue_t link;
}ngx_qtest_t;

int main(void)
{
	ngx_qtest_t arr[5];
	ngx_queue_t head;
	ngx_queue_init(&head);
	int i=0;
		printf("====%d==111==\n", 0);
	for(; i<5; ++i){
		arr[i].key = i;
		sprintf(arr[i].name, "my key is :%d", arr[i].key);
		
		if(i%2){
			printf("==1==%d====\n", i);
			ngx_queue_insert_head(&head, &arr[i].link);
		}else{
			printf("==2==%d====\n", i);
			ngx_queue_insert_tail(&head, &arr[i].link);
		}
	}
	ngx_queue_t *tmp = ngx_queue_head(&head);
	for(i=0; i<5;i++){
		ngx_qtest_t *data = ngx_queue_data(tmp, ngx_qtest_t, link);             
		printf("====%d====\n", data->key);
		tmp = ngx_queue_next(tmp); 
		
	}
	
	printf("---offsetof link in ngx_qtest_t: %d \n", offsetof(ngx_qtest_t, link));
    return 0;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46