nginx源码分析-字符串

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 nginx源码分析-字符串,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129638.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!