nginx源码分析-字符串

1.源码分析

1.1初始结构

ngx str 并不是一 个传统意义上的“字符串”,准确地说,它应该是 个“内存块引用”,
义如
typedef struct {
    size_t      len;
    u_char     *data;
} ngx_str_t;

从代码里可以看到, ngx str 的结构非常简单,只是用成员变量 len和 data 标记了 一 块内 存区域,并不实际持有 个字符串内容,非常的轻量级。 data 成员的类型是 u_ char 而不是 c har 意味着它不 定必须 以’/0" 结尾 任何 数据都可以当作字符串来使用。
当然 这种设计也有缺点 因为 ngx_ str_t  只是引用内存,所以我们应尽量以“只读”的方
式去使 用它 在多个 ngx_str_t 共享 块内存时要小心,如果擅自修改字符串内容很有可能
影响其 他的 ngx str 引用,导致错误发生。另一 种危险是引用的内存地址可能 会失效
访问 到错误的内存区域

1.2.成员函数

1.2.1初始化赋值

Nginx提供两个初始化函数宏:ngx_string()使用字符串初始化,ngx_null_string ()初始化为一个空字符串,因为它们使用了{...}的形式,所以只能用于赋值初始化:

#define ngx_string(str)     { sizeof(str) - 1, (u_char *) str }
#define ngx_null_string     { 0, NULL }

设置内容:

运行时设置字符串内容可以使用下面两个函数宏,功能是相同的,注意参数str必须是指针:

#define ngx_str_set(str, text)                                               \
    (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text
#define ngx_str_null(str)   (str)->len = 0; (str)->data = NULL

ngx_string ()和 ngx_str_set()内部使用了sizeof计算字符串长度,所以参数必须是一个编译期的字符串“字面值”,而不能是一个字符串指针,否则sizeof 会计算得到指针的长度(8字节),而不是字符串的实际长度。

用法示例:

ngx_str_t s1=ngx_null_string;
ngx_str_t s2=ngx_string("matrix");

ngx_str_set(&s1,"reload");
ngx_str_null(&s2);

1.2.1基本操作函数

转化大小写

#define ngx_tolower(c)      (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#define ngx_toupper(c)      (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)

大小比较

ngx_str_t 只是个普通的字符串,所以标准的c字符串函数都能够使用(需要转型为const char*),处理它的data成员就可以了,但Nginx也实现了一些特有的操作函数。

下面是一些常用的字符串操作函数,但需要注意有的参数类型不是ngx_str_t,而是u _char* :

#define ngx_strncmp(s1, s2, n)  strncmp((const char *) s1, (const char *) s2, n)


/* msvc and icc7 compile strcmp() to inline loop */
#define ngx_strcmp(s1, s2)  strcmp((const char *) s1, (const char *) s2)


#define ngx_strstr(s1, s2)  strstr((const char *) s1, (const char *) s2)
                                                                                  

格式化函数

_char * ngx_cdecl
ngx_sprintf(u_char *buf, const char *fmt, ...)
{
    u_char   *p;
    va_list   args;

    va_start(args, fmt);
    p = ngx_vslprintf(buf, (void *) -1, fmt, args);
    va_end(args);

    return p;
}
u_char * ngx_cdecl
ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
{
    u_char   *p;
    va_list   args;

    va_start(args, fmt);
    p = ngx_vslprintf(buf, buf + max, fmt, args);
    va_end(args);

    return p;
}


u_char * ngx_cdecl
ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
{
    u_char   *p;
    va_list   args;

    va_start(args, fmt);
    p = ngx_vslprintf(buf, last, fmt, args);
    va_end(args);

    return p;
}

ngx_sprintf ( )直接向buf输出格式化内容,不检查缓冲区的有效性,存在缓冲区溢出危险,通常不建议使用。后两个函数比较安全,参数max和 last指明了缓冲区的结束位置,所以格式化的结果只会填满缓冲区为止。

2.c++封装

2.1初始化

#define typed_ngx_string(str) ngx_str_t ngx_string(str)
#define typed_ngx_null_string ngx_str_t ngx_null_string


public:
    typedef NgxWrapper<ngx_str_t> super_type;
    typedef NgxString this_type;

    typedef boost::string_ref string_ref_type;

public:
    NgxString(ngx_str_t& str):
        super_type(str)
    {}

    // enable convert const object
    NgxString(const ngx_str_t& str):
        super_type(const_cast<ngx_str_t&>(str))
    {}

    // disable temporary object
    NgxString(ngx_str_t&& str) = delete;

    ~NgxString() = default;

1.NgxWrapper相当于一个基本的模块类型(封装各种各样的数据结构)

2.有一个新特性 const_cast 

:const_cast<type_id> (expression)

该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。

一、常量指针被转化成非常量的指针,并且仍然指向原来的对象;

二、常量引用被转换成非常量的引用,并且仍然指向原来的对象;

三、const_cast一般用于修改底指针。如const char *p形式。

3. 有一个巧妙设计  NgxString(ngx_str_t&& str) = delete;

将对象转化成str!!!

2.2访问函数

public:
    const char* data() const
    {
        return reinterpret_cast<const char*>(get()->data);
    }

    std::size_t size() const
    {
        return get()->len;
    }

    bool empty() const
    {
        return !get()->data || !get()->len;
    }

    string_ref_type str() const
    {
        return string_ref_type(data(), size());
    }
    }
public:
    // nagetive means error
    operator ngx_int_t () const
    {
        return ngx_atoi(get()->data, get()->len);
    }

1.首先提供data()和size()提供访问

2.判断空和转换char-》int

2.3引入c++的iterator特性质

public:
    // range concept
    typedef u_char  char_type;
    typedef u_char* iterator;
    typedef iterator const_iterator;
    typedef boost::iterator_difference<iterator> difference_type;
public:
    const_iterator begin() const
    {
        return get()->data;
    }

    const_iterator end() const
    {
        return get()->data + get()->len;
    }

public:
    const char_type& front() const
    {
        return *begin();
    }
    const char_type& back() const
    {
        //return *std::prev(end());
        return *boost::prior(end());
    }
public:
    bool contains(const this_type& x) const
    {
        return boost::contains(*this, x);
    }

1.理解u_char 和u_char*

  1.指针传递,就是把改变的地址传过去了,你在第一个函数里修改里地址里的内容,所以a改变了
  2.值传递,值传递只是拷贝了一份,作为参数,不影响原来的值 

  3.引用是原变量的一个别名,跟原来的变量实质上是同一个东西。

int a = 996;
int *p = &a; // p是指针, &在此是求地址运算
int &r = a; // r是引用, &在此起标识作用

总结就是一个是返回变量值,一个是内存值

public:
    template<typename T>
    friend T& operator<<(T& o, const this_type& s)
    {
        o.write(s.data(), s.size());
        return o;
    }

public:
    template<typename T>
    friend T& operator<<(T& o, const this_type& s)
    {
        o.write(s.data(), s.size());
        return o;
    }

    template<typename T>
    friend T& operator<<(T& o, const ngx_str_t& s)
    {
       o.write(reinterpret_cast<const char*>(s.data), s.len);
       return o;
    }

    template<typename T>
    friend T& operator<<(T& o, const volatile ngx_str_t& s)
    {
        o.write(reinterpret_cast<const char*>(s.data), s.len);
        return o;
    }

 
public:
    template<typename ... Args>
    void printf(const Args& ... args) const
    {
        auto p = ngx_snprintf(get()->data, get()->len, args ...);
        get()->len = static_cast<std::size_t>(p - get()->data);
    }
};

1.重载<<(c++cin<<)相似

2.重载两种类型

 volatile的本意是“易变的”,volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

const就不多说啦

3.printf相同!!!借鉴啦上面的ngx_snprintf

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值