1.数据类型
1.1基本数据
Nginx主要使用了三个标准整数类型: size_t、 u_char和off_t。
size_t用于计算数据的长度,是C/C++标准里定义的一个类型,是 sizeof 操作符的结果类型,相当于unsigned_long。在64位的系统里宽度是8字节:
u_char表示一个字节,虽然它也是一个标准整数类型,但并不是C/C++标准,而是“系统标准”,是在<sys/types.h>里的一个typedef:
typedef unsigned char u_char
1.2自定义
Nginx依据C/C++标准重新定义了三个整数类型来代替标准里的int/long 等类型,编译都能获得一致的结果。这些类型是:
typedef intptr_t ngx_int_t;
typedef uintptr_t ngx_uint_t;
typedef intptr_t ngx_flag_t;
还有很多在其他模块。
我们在开发 Nginx 块编写代码时应该尽量使用这些 Nginx 专有的整数类型,不仅是为
了与 Ngin 保持风格的一致,更重要的是保证代码的跨平台兼容
1.3无效值
变量的初始化是编程语言里一个重要但又常常会被忽略的问题。在C/C++中,整数类型属于POD类型,初始值是“未定义”的,也就是说初始值可能是任意数值,存在安全隐患。
Lua/Python等语言有Nil/None 的概念,一个变量如果未初始化,那么它的值就是Nil或者None。Nginx采用了类似思路的“UNSET”值,使用“-1”表示未初始化。
由于C/C++是强类型语言,单纯的整数-1不能直接与其他类型比较,需要做类型转换,所以Nginx为-1定义了不同类型转换的宏:
#define NGX_CONF_UNSET -1 //通用无效值
#define NGX_CONF_UNSET_UINT (ngx_uint_t) -1 //无符号整数
#define NGX_CONF_UNSET_PTR (void *) -1 //指针
#define NGX_CONF_UNSET_SIZE (size_t) -1 //size_t 类型的无效值
#define NGX_CONF_UNSET_MSEC (ngx_msec_t) -1 //毫秒的无效值
#define ngx_conf_init_value(conf, default) \
if (conf == NGX_CONF_UNSET) { \
conf = default; \
}
#define ngx_conf_init_ptr_value(conf, default) \
if (conf == NGX_CONF_UNSET_PTR) { \
conf = default; \
}
#define ngx_conf_init_uint_value(conf, default) \
if (conf == NGX_CONF_UNSET_UINT) { \
conf = default; \
}
#define ngx_conf_init_size_value(conf, default) \
if (conf == NGX_CONF_UNSET_SIZE) { \
conf = default; \
}
#define ngx_conf_init_msec_value(conf, default) \
if (conf == NGX_CONF_UNSET_MSEC) { \
conf = default; \
}
2.c++封装数据类型
2.1封装无效值
class NgxUnsetValue final
{
public:
template<typename T>
operator T()const
{
return static_cast<T>(-1);
}
//指针和整数之间的转换
template<typename T>
operator T*()const
{
return reinterpret_cast<T*>(-1);
}
//
//NgxUnsetvalue应该是个单件
//,可以实现一个静态成员函数
//,提供一个全局访问点:
public:
static const NgxUnsetValue&get()
{
static NgxUnsetValue const v={};//空类
return v;
}
} ;
解析1
1.首先利用模板技术比宏安全实现了任意封装类型的无效值。
2.NgxUnsetvalue应该是个单件,可以实现一个静态成员函数,提供一个全局访问点:
auto &&ngx_nil=NgxUnsetValue::get()
2.2操作函数封装
2.1.1判断是否无效
public:
template<typename T,typename ... Args>
static void unset(T&v,Args ... arg)
{
v=NgxUnsetValue::get();
unset(arg...);
}
void unset(){};
public:
template<typename T>
static bool invaild(const T&v)
{
return v==static_cast<T>(NgxUnsetValue::get());
}
template<typename T,typename U>
static void init(T&x,const U&v)
{
if(invaild(x))
{
return x=v;
}
}
public:
template<typename T,typename U,typename V>
static void merge(T&c,const U&p,const V&d)
{
if(invaild(c))
{
c=invaild(p)?d:p;
}
}
思想
1.先判断是否为有效值
2.采用参数系列,使用递归来判断多个值;
3.单个值是否有效,在初始化一个值
4.一个值是否有效,再初始化两个值
2.2.2重载
namespace cwr {
auto &&ngx_nil=NgxUnsetValue::get();
};
template <typename T>
bool operator==(const T&x,const NgxUnsetValue&)
{
return NgxValue::invalid(x);
}
template<class T>
bool operator!=(const T&x,const NgxUnsetValue&)
{
return !NgxValue::invaild(x);
}