1.源码分析
1.1初始结构
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