redis之sds(simple dynamic string)阅读笔记1--创建新sds字符串
redis之sds(simple dynamic string)阅读笔记1--创建新sds字符串 我们想要定义一个新的sds,如下 sds mysds = sdsnew("test for sds !\n"); 中间经历了什么呢? 首先调用函数sdsnew ************************************** sds sdsnew(const char *init) { size_t initlen = (init == NULL) ? 0 : strlen(init); //如果不为空窜,那么获取字符串长度 return sdsnewlen(init, initlen); //调用函数sdsnewlen } ************************************** 现在我们需要进入函数sdsnewlen,看里面干了些什么 为了弄清楚里面的逻辑,我们先要做些准备工作,提前熟悉里面调用的函数 函数1 sdsReqType 根据字符串长度返回字符串类型(inline表示内联函数,编译时会自动展开)具体如下 ************************************************************ static inline char sdsReqType(size_t string_size) { if (string_size < 1<<5) return SDS_TYPE_5; if (string_size < 1<<8) return SDS_TYPE_8; if (string_size < 1<<16) // 1<<16 = 65536 return SDS_TYPE_16; //LONG_MAX == long int 9223372036854775807 = 0x7fffffffffffffff //LLONG_MAX == long long int 7fffffffffffffff #if (LONG_MAX == LLONG_MAX) //相等 表示在64位系统中 if (string_size < 1ll<<32) //注意后面两个是字母L的小写 return SDS_TYPE_32; return SDS_TYPE_64; #else return SDS_TYPE_32; //不相等,在32位系统中,直接返回32类型 #endif } ********************************************************* 函数2 sdsHdrSize 返回对应字符串结构体的大小 ********************************************************* static inline int sdsHdrSize(char type) { switch(type&SDS_TYPE_MASK) { //这里 &SDS_TYPE_MASK 似乎多余 case SDS_TYPE_5: return sizeof(struct sdshdr5); case SDS_TYPE_8: return sizeof(struct sdshdr8); case SDS_TYPE_16: return sizeof(struct sdshdr16); case SDS_TYPE_32: return sizeof(struct sdshdr32); case SDS_TYPE_64: return sizeof(struct sdshdr64); } return 0; } ********************************************************* 宏1 SDS_HDR_VAR 获取指向结构体的指针 ********************************************************* #define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T))); 其中T是数字(5,8,16,32,64),s是sds类型的字符串 观察如下结构体 struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* used */ uint8_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; s 表示字符串s所在的内存开始地址,即buf sizeof(struct sdshdr##T) 表示对应结构体的大小,即 len的长度 + alloc的长度 + flags的长度 那么 (s) - (sizeof(struct sdshdr##T) ) 就是字符串所在结构体的初始内存地址,故可以赋值给struct sdshdr##T *sh 这里为什么要用小括号包裹起来,防止宏定义展开的时候出现问题 ********************************************************* 接下来我们就可以开始看函数sdsnewlen了 ********************************************************* sds sdsnewlen(const void *init, size_t initlen) { void *sh; sds s; char type = sdsReqType(initlen); //获取需要创建字符串的类型 /* Empty strings are usually created in order to append. Use type 8 * since type 5 is not good at this. */ if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; int hdrlen = sdsHdrSize(type); //获取对应类型结构体的大小 unsigned char *fp; /* flags pointer. */ sh = s_malloc(hdrlen+initlen+1); //分配内存 结构体大小 + 字符串大小 + \0 if (sh == NULL) return NULL; if (init==SDS_NOINIT) init = NULL; else if (!init) memset(sh, 0, hdrlen+initlen+1); //将分配的内存清空 s = (char*)sh+hdrlen; //获取指向字符数组开始的位置 fp = ((unsigned char*)s)-1; //获取指向结构体成员变量flags的地址, (unsigned char*)s 是强转获取s中一个字节的地址 switch(type) { //这里 SDS_TYPE_5 部分的代码可以去除了,没有必要再留在这里 case SDS_TYPE_5: { *fp = type | (initlen << SDS_TYPE_BITS); //腾出最小的3位作为标志位 break; } case SDS_TYPE_8: { SDS_HDR_VAR(8,s); //获取指向结构体的指针 sh->len = initlen; // 字符串长度 sh->alloc = initlen; //分配给字符串的长度 *fp = type; //字符串类型 break; } case SDS_TYPE_16: { SDS_HDR_VAR(16,s); sh->len = initlen; sh->alloc = initlen; *fp = type; break; } case SDS_TYPE_32: { SDS_HDR_VAR(32,s); sh->len = initlen; sh->alloc = initlen; *fp = type; break; } case SDS_TYPE_64: { SDS_HDR_VAR(64,s); sh->len = initlen; sh->alloc = initlen; *fp = type; break; } } if (initlen && init) //如果传入字符串init不为空,并且分配的内存长度initlen不为0 memcpy(s, init, initlen); //将字符串init的initlen长度的串拷贝到s中 s[initlen] = '\0'; 最后一个字符用作结尾 return s; //返回得到的字符串 }