指针的本质--u_char*指针在Nginx源码中的应用及原因

本文探讨了Nginx内存池中使用u_char*指针的原因,分析了其作为字节地址的优势,以及在内存管理中的移动和转换操作。通过示例展示了指针类型对内存分配的影响,强调了u_char*在位移运算中的便捷性,对比了与其他类型指针的区别。

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*



/opt/nginx-sticky-module/ngx_http_sticky_misc.c: 在函数‘ngx_http_sticky_misc_sha1’中: /opt/nginx-sticky-module/ngx_http_sticky_misc.c:176:15: 错误:‘SHA_DIGEST_LENGTH’未声明(在此函数内第一次使用) u_char hash[SHA_DIGEST_LENGTH]; ^ /opt/nginx-sticky-module/ngx_http_sticky_misc.c:176:15: 附注:每个未声明的标识符在其出现的函数内只报告一次 /opt/nginx-sticky-module/ngx_http_sticky_misc.c:176:10: 错误:未使用的变量‘hash’ [-Werror=unused-variable] u_char hash[SHA_DIGEST_LENGTH]; ^ /opt/nginx-sticky-module/ngx_http_sticky_misc.c: 在函数‘ngx_http_sticky_misc_hmac_sha1’中: /opt/nginx-sticky-module/ngx_http_sticky_misc.c:242:15: 错误:‘SHA_DIGEST_LENGTH’未声明(在此函数内第一次使用) u_char hash[SHA_DIGEST_LENGTH]; ^ /opt/nginx-sticky-module/ngx_http_sticky_misc.c:243:12: 错误:‘SHA_CBLOCK’未声明(在此函数内第一次使用) u_char k[SHA_CBLOCK]; ^ /opt/nginx-sticky-module/ngx_http_sticky_misc.c:243:10: 错误:未使用的变量‘k’ [-Werror=unused-variable] u_char k[SHA_CBLOCK]; ^ /opt/nginx-sticky-module/ngx_http_sticky_misc.c:242:10: 错误:未使用的变量‘hash’ [-Werror=unused-variable] u_char hash[SHA_DIGEST_LENGTH]; ^ /opt/nginx-sticky-module/ngx_http_sticky_misc.c: 在函数‘ngx_http_sticky_misc_text_raw’中: /opt/nginx-sticky-module/ngx_http_sticky_misc.c:324:5: 错误:传递‘ngx_sock_ntop’的第 1 个参数时将整数赋给指针,未作类型转换 [-Werror] digest->len = ngx_sock_ntop(1); ^ In file included from src/core/ngx_core.h:82:0, from /opt/nginx-sticky-module/ngx_http_sticky_misc.c:8: src/core/ngx_inet.h:114:8: 附注:需要类型‘struct sockaddr *’,但实参的类型为‘int’ size_t ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, ^ /opt/nginx-sticky-module/ngx_http_sticky_misc.c:324:5: 错误:提供给函数‘ngx_sock_ntop’的实参太少 digest->len = ngx_sock_ntop(1); ^
06-24
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值