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; //返回得到的字符串
}

我们就这样创建了一个sds新字符串!

猜你喜欢

转载自www.cnblogs.com/cquccy/p/13368267.html