GNU下的void *p++相当于char *p++ 也就是移动一个字节。
下面的代码是Nginx中内存池的结构体代码,其中last和end是表示内存地址的。
last是u_char*指针类型也就是unsigned char
typedef struct { u_char *last; u_char *end; ngx_pool_t *next; ngx_uint_t failed; } ngx_pool_data_t;
由于unsigned char*指针表示一个字节 所以是0-255之间
257已经需要2个字节10000001,所以如果用unsigned char*类型来声明该段地址(&k),那么多出的部分会被舍去,所以如果对其解引用就是00000001,而不是257
本来,指针变量不管是什么类型其实都完整的存储了“地址”,但是不同类型解引用就会产生对应的值!
nginx移动last指针,分配内存的函数
void * ngx_palloc(ngx_pool_t *pool, size_t size) { u_char *m; ngx_pool_t *p; if (size <= pool->max) { p = pool->current; do { m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); if ((size_t) (p->d.end - m) >= size) { p->d.last = m + size; return m; } p = p->d.next; } while (p); return ngx_palloc_block(pool, size); } return ngx_palloc_large(pool, size); }声明了一个u_char*m的变量,然后返回给空指针。其实,声明last为空指针也可以,那样要如这里: 指针的本质-void和void*指针在nginx中的应用
感觉自己2篇文章其实还是在说指针,讲同一个东西。
如果需要增加内存
static void * ngx_palloc_block(ngx_pool_t *pool, size_t size) { u_char *m; size_t psize; ngx_pool_t *p, *new, *current; psize = (size_t) (pool->d.end - (u_char *) pool); m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log); if (m == NULL) { return NULL; } new = (ngx_pool_t *) m; new->d.end = m + psize; new->d.next = NULL; new->d.failed = 0; m += sizeof(ngx_pool_data_t); m = ngx_align_ptr(m, NGX_ALIGNMENT); new->d.last = m + size; current = pool->current; for (p = current; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) { current = p->d.next; } } p->d.next = new; pool->current = current ? current : new; return m; }先是声明一个u_char *m; 后面给其分配内存。
然后是讲*m转化为ngx_pool_t *new= (ngx_pool_t *) m;
然后把new串到p上,p也就是前面已经分配了的内存池(由于空间不够需要扩容)
最后,返回m。最关键就是m 注意:m和new后来就完全不一样了,因为m是last指针,也就是新分配的内存地址!
对于调用ngx_palloc()函数的变量来说,由于ngx_palloc()返回的是void*指针,所以可以给任意其他类型指针!
总结:
因为u_char*和char*指针都是指向1个字节的地址,所以用u_char*和char*指针进行位移运算是非常方便的!这也是为什么nginx用u_char*做last指针类型的原因
设想如果用的是Int*,那么last+1实际上就是+4个字节,非常不方便。
其实用void*也可以定义last指针的,但是这样需要做一次转换在运算的时候!
所谓内存池,就是划一块内存,从内存池中申请就是返回一个地址,和malloc一样本质都是返回一个地址,准确的说是void*!