• nginx源码分析-字符串


    1.源码分析

    1.1初始结构

    ngx str 并不是一 个传统意义上的“字符串”,准确地说,它应该是 个“内存块引用”,
    义如
    1. typedef struct {
    2. size_t len;
    3. u_char *data;
    4. } 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 ()初始化为一个空字符串,因为它们使用了{...}的形式,所以只能用于赋值初始化:

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

    设置内容:

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

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

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

    用法示例:

    1. ngx_str_t s1=ngx_null_string;
    2. ngx_str_t s2=ngx_string("matrix");
    3. ngx_str_set(&s1,"reload");
    4. ngx_str_null(&s2);

    1.2.1基本操作函数

    转化大小写

    1. #define ngx_tolower(c) (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
    2. #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* :

    1. #define ngx_strncmp(s1, s2, n) strncmp((const char *) s1, (const char *) s2, n)
    2. /* msvc and icc7 compile strcmp() to inline loop */
    3. #define ngx_strcmp(s1, s2) strcmp((const char *) s1, (const char *) s2)
    4. #define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2)

    格式化函数

    1. _char * ngx_cdecl
    2. ngx_sprintf(u_char *buf, const char *fmt, ...)
    3. {
    4. u_char *p;
    5. va_list args;
    6. va_start(args, fmt);
    7. p = ngx_vslprintf(buf, (void *) -1, fmt, args);
    8. va_end(args);
    9. return p;
    10. }
    11. u_char * ngx_cdecl
    12. ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
    13. {
    14. u_char *p;
    15. va_list args;
    16. va_start(args, fmt);
    17. p = ngx_vslprintf(buf, buf + max, fmt, args);
    18. va_end(args);
    19. return p;
    20. }
    21. u_char * ngx_cdecl
    22. ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
    23. {
    24. u_char *p;
    25. va_list args;
    26. va_start(args, fmt);
    27. p = ngx_vslprintf(buf, last, fmt, args);
    28. va_end(args);
    29. return p;
    30. }

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

    2.c++封装

    2.1初始化

    1. #define typed_ngx_string(str) ngx_str_t ngx_string(str)
    2. #define typed_ngx_null_string ngx_str_t ngx_null_string
    3. public:
    4. typedef NgxWrapper<ngx_str_t> super_type;
    5. typedef NgxString this_type;
    6. typedef boost::string_ref string_ref_type;
    7. public:
    8. NgxString(ngx_str_t& str):
    9. super_type(str)
    10. {}
    11. // enable convert const object
    12. NgxString(const ngx_str_t& str):
    13. super_type(const_cast<ngx_str_t&>(str))
    14. {}
    15. // disable temporary object
    16. NgxString(ngx_str_t&& str) = delete;
    17. ~NgxString() = default;

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

    2.有一个新特性 const_cast 

    :const_cast (expression)

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

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

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

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

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

    将对象转化成str!!!

    2.2访问函数

    1. public:
    2. const char* data() const
    3. {
    4. return reinterpret_cast<const char*>(get()->data);
    5. }
    6. std::size_t size() const
    7. {
    8. return get()->len;
    9. }
    10. bool empty() const
    11. {
    12. return !get()->data || !get()->len;
    13. }
    14. string_ref_type str() const
    15. {
    16. return string_ref_type(data(), size());
    17. }
    18. }
    19. public:
    20. // nagetive means error
    21. operator ngx_int_t () const
    22. {
    23. return ngx_atoi(get()->data, get()->len);
    24. }

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

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

    2.3引入c++的iterator特性质

    1. public:
    2. // range concept
    3. typedef u_char char_type;
    4. typedef u_char* iterator;
    5. typedef iterator const_iterator;
    6. typedef boost::iterator_difference difference_type;
    7. public:
    8. const_iterator begin() const
    9. {
    10. return get()->data;
    11. }
    12. const_iterator end() const
    13. {
    14. return get()->data + get()->len;
    15. }
    16. public:
    17. const char_type& front() const
    18. {
    19. return *begin();
    20. }
    21. const char_type& back() const
    22. {
    23. //return *std::prev(end());
    24. return *boost::prior(end());
    25. }
    26. public:
    27. bool contains(const this_type& x) const
    28. {
    29. return boost::contains(*this, x);
    30. }

    1.理解u_char 和u_char*

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

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

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

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

    1. public:
    2. template<typename T>
    3. friend T& operator<<(T& o, const this_type& s)
    4. {
    5. o.write(s.data(), s.size());
    6. return o;
    7. }
    8. public:
    9. template<typename T>
    10. friend T& operator<<(T& o, const this_type& s)
    11. {
    12. o.write(s.data(), s.size());
    13. return o;
    14. }
    15. template<typename T>
    16. friend T& operator<<(T& o, const ngx_str_t& s)
    17. {
    18. o.write(reinterpret_cast<const char*>(s.data), s.len);
    19. return o;
    20. }
    21. template<typename T>
    22. friend T& operator<<(T& o, const volatile ngx_str_t& s)
    23. {
    24. o.write(reinterpret_cast<const char*>(s.data), s.len);
    25. return o;
    26. }
    27. public:
    28. template<typename ... Args>
    29. void printf(const Args& ... args) const
    30. {
    31. auto p = ngx_snprintf(get()->data, get()->len, args ...);
    32. get()->len = static_castsize_t>(p - get()->data);
    33. }
    34. };

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

    2.重载两种类型

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

    const就不多说啦

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

  • 相关阅读:
    竞赛 机器视觉的试卷批改系统 - opencv python 视觉识别
    linux下的进程管理
    如何在 WSL 下实现 NGINX 反向代理
    unity 曲线可视化图表制作
    [正确重装docker] Win10 重装 Docker 提示 Exising installation is up to date 的正确姿势
    Yolo5部署到Jetson_orin上错误笔记记录
    简单聊聊大数据
    vue3+ts插槽的使用
    ES6对象
    编写脚本顺便浅浅学一下乱七八糟的库
  • 原文地址:https://blog.csdn.net/qq_62309585/article/details/127938835