近来想拜读一下优秀的开源代码设计,之前也阅读过qt以及opencv的源码,不过学习nginx源码的目的是想试着用设计模式以及C++的思想来封装一次nginx的源码,但是第一步还得好好熟悉一下nginx,大师们都说过,最好的办法就是看源码,万能的开源。
ngx_str_t是nginx中定义的类似于字符串的结构,其中包含了字符串的长度(不包含终止字符'\0')以及字符串的首地址,数据结构定义如下:
typedef struct {
size_t len;
u_char *data;
} ngx_str_t;
细心的人都会觉得,以首地址的方式指向一块内存,如果在改变ngx_str_t定义的字符串的时候,可能会出错。因为它指向的是一块内存的首地址,如果改变字符串内容,有可能使得指向内存的区域进入到别的字符串的区域,这样就会出现差错。所以,对于ngx_str_t最好的方式是以只读的方式进行。
#define ngx_string(str) { sizeof(str) - 1, (u_char *) str }
#define ngx_null_string { 0, NULL }
#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_str_t s1=ngx_null_string;
ngx_str_t s2=ngx_string("hello nginx");
ngx_str_set(&s2,"hello again hello");
ngx_str_null(&s2);
很多是封装的c下面的string.h文件中的函数:
#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) //转大写字符
void ngx_strlow(u_char *dst, u_char *src, size_t n); //从src复制n个字符到dst中,同时将相应的字符转为小写字符
#define ngx_strncmp(s1, s2, n) strncmp((const char *) s1, (const char *) s2, n) //字符比较函数,只比较前面n个字符,大小写敏感
#define ngx_strcmp(s1, s2) strcmp((const char *) s1, (const char *) s2) //字符比较函数,一直到某个字符的终止位置,大小写敏感
#define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2) //查找子串
#define ngx_strlen(s) strlen((const char *) s) //计算字符穿长度
#define ngx_strchr(s1, c) strchr((const char *) s1, (int) c) //第一次出现c的位置
自定义函数:
ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2);
ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n); //以上两个函数类似与ngx_strcmp,ngx_strncmp,大小写不敏感
u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...);
u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt,
ngx_cdecl是一个宏定义,原型为_cdecl,表示函数的参数从从右到左依次入账,是默认的函数调用方法,用到这个是因为以上三个参数用到了省略号参数,参数个数是可变的。以ngx_snprintf为例进行讲解:
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;
}
在ngx_snprintf中,fmt是可变参数,我们都知道,printf里面会有"%d%d%s"这种类似的格式,那么这里的fmt也是一样的。ngx_snprintf的格式参数包含:
/*
* supported formats:
* %[0][width][x][X]O off_t
* %[0][width]T time_t
* %[0][width][u][x|X]z ssize_t/size_t
* %[0][width][u][x|X]d int/u_int
* %[0][width][u][x|X]l long
* %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
* %[0][width][u][x|X]D int32_t/uint32_t
* %[0][width][u][x|X]L int64_t/uint64_t
* %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
* %[0][width][.width]f double, max valid number fits to %18.15f
* %P ngx_pid_t
* %M ngx_msec_t
* %r rlim_t
* %p void *
* %V ngx_str_t *
* %v ngx_variable_value_t *
* %s null-terminated string
* %*s length and string
* %Z '\0'
* %N '\n'
* %c char
* %% %
*
* reserved:
* %t ptrdiff_t
* %S null-terminated wchar string
* %C wchar
*/
以上三个函数都调用了函数:
u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args);
它是实现最终的格式化输出到buf的函数。
复制函数
u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n);
u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src);
#include
#include
#include
int main(int args,char *argv[])
{
u_char *p;
ngx_str_t str = ngx_null_string;
unsigned char buffer[1024];
printf("str長度爲:%d\n",(int)str.len);
ngx_str_set(&str,"hello world"); //注意是&str而不是str
p=ngx_snprintf(buffer, str.len, "%V", &str); //注意是&str而不是str
buffer[str.len]='\0';
printf("格式化str輸出爲:%s\n",buffer);
printf("格式化長度爲:%d\n",(int)((p-buffer)/sizeof(char))); //p返回的是最後輸出的位置,所以由此可以得出最後格式化的字符個數
return 1;
}