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);
    }