redis源码之sds
? ? ? ? sds是redis中一個(gè)很重要的數(shù)據(jù)結(jié)構(gòu),今天看學(xué)一下它源碼的實(shí)現(xiàn)。
typedef char *sds;/* Note: sdshdr5 is never used, we just access the flags byte directly.* However is here to document the layout of type 5 SDS strings. */ struct __attribute__ ((__packed__)) sdshdr5 {unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ //flags字段的高5bits保存字符串實(shí)際長(zhǎng)度char buf[]; }; struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* used */ //有效字符串長(zhǎng)度uint8_t alloc; /* excluding the header and null terminator */ //alloc-分配的內(nèi)存空間長(zhǎng)度unsigned char flags; /* 3 lsb of type, 5 unused bits */ //頭部類(lèi)型char buf[]; }; struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* used */uint16_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[]; }; struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* used */uint32_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[]; }; struct __attribute__ ((__packed__)) sdshdr64 {uint64_t len; /* used */uint64_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[]; };#define SDS_TYPE_5 0 #define SDS_TYPE_8 1 #define SDS_TYPE_16 2 #define SDS_TYPE_32 3 #define SDS_TYPE_64 4 #define SDS_TYPE_MASK 7 #define SDS_TYPE_BITS 3 #define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T))); #define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) #define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)__attribute__ ((__packed__))是避免內(nèi)存字節(jié)對(duì)齊節(jié)省內(nèi)存,上面定義了5個(gè)結(jié)構(gòu)體,redis會(huì)根據(jù)字符串的長(zhǎng)度來(lái)選擇合適的結(jié)構(gòu)體,每個(gè)結(jié)構(gòu)體有對(duì)應(yīng)數(shù)據(jù)部分和頭部。下面具體學(xué)習(xí)sds 的一些API。
static inline int sdsHdrSize(char type) {//根據(jù)結(jié)構(gòu)體類(lèi)型返回sds頭部長(zhǎng)度(頭部字節(jié)相加的結(jié)果)switch(type & SDS_TYPE_MASK) {case SDS_TYPE_5:return sizeof(struct sdshdr5); //1 sdshdr5對(duì)應(yīng)buf里面沒(méi)有設(shè)定大小,應(yīng)為空case SDS_TYPE_8:return sizeof(struct sdshdr8); //3case SDS_TYPE_16:return sizeof(struct sdshdr16); //5 case SDS_TYPE_32:return sizeof(struct sdshdr32); //9case SDS_TYPE_64:return sizeof(struct sdshdr64); //17}return 0; }static inline char sdsReqType(size_t string_size) { 根據(jù)size來(lái)選取合適的結(jié)構(gòu)體if (string_size < 1<<5) //1<<5 = 32。SDS_TYPE_5 高5位存儲(chǔ)字符串的實(shí)際長(zhǎng)度,低3位存儲(chǔ)typereturn SDS_TYPE_5;if (string_size < 1<<8) //1<<8 = 256 SDS_TYPE_8用8個(gè)位存儲(chǔ)長(zhǎng)度return SDS_TYPE_8;if (string_size < 1<<16) //1<<16 = 65526return SDS_TYPE_16; #if (LONG_MAX == LLONG_MAX)if (string_size < 1ll<<32)return SDS_TYPE_32;return SDS_TYPE_64; #elsereturn SDS_TYPE_32; #endif }sdsReqType中的string_size是對(duì)應(yīng)字符串的長(zhǎng)度,這里注意每種結(jié)構(gòu)體能存儲(chǔ)串長(zhǎng)是不一樣的,因?yàn)榇L(zhǎng)的位不一樣。sdsHdrSize用來(lái)獲取對(duì)應(yīng)的type的頭部長(zhǎng)度。
sds sdsnewlen(const void *init, size_t initlen) {//根據(jù)給定的初始化字符串 init 和字符串長(zhǎng)度 initlen,創(chuàng)建一個(gè)新的sdsvoid *sh;sds s; //字符串char *char type = sdsReqType(initlen); 根據(jù)sds長(zhǎng)度選擇結(jié)構(gòu)體類(lèi)型,/* 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; //SDS_TYPE_5int hdrlen = sdsHdrSize(type); 返回相應(yīng)結(jié)構(gòu)體頭部對(duì)應(yīng)的大小unsigned char *fp; /* flags pointer. */sh = s_malloc(hdrlen+initlen+1); //分配內(nèi)存 initlen+2 ,利用結(jié)構(gòu)體的大小分配內(nèi)存if (init==SDS_NOINIT)init = NULL;else if (!init)memset(sh, 0, hdrlen+initlen+1); //初始化if (sh == NULL) return NULL;s = (char*)sh+hdrlen; //指向第一個(gè)有效數(shù)據(jù)fp = ((unsigned char*)s)-1; //fp指向flagswitch(type) {case SDS_TYPE_5: {*fp = type | (initlen << SDS_TYPE_BITS);//0000 0011 << 3 = 0001 1000 //高5位保存字符串的長(zhǎng)度,低3位保存的是typebreak;}case SDS_TYPE_8: {SDS_HDR_VAR(8,s);//讓sh指向整個(gè)結(jié)構(gòu)體的起始地址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)memcpy(s, init, initlen);s[initlen] = '\0';return s; }sdsnewlen函數(shù)根據(jù)傳入的initlen的大小會(huì)選擇不同的結(jié)構(gòu)體類(lèi)型。
void sdsfree(sds s) {if (s == NULL) return;s_free((char*)s-sdsHdrSize(s[-1])); }sdsfree這里的s是指向第一個(gè)有效數(shù)據(jù)的,sdsHdrSize(s[-1]))返回其對(duì)應(yīng)的頭結(jié)構(gòu)大小,(char*)s-sdsHdrSize(s[-1])的結(jié)果就是s指向結(jié)構(gòu)體的首地址。
/* Modify an sds string in-place to make it empty (zero length).* However all the existing buffer is not discarded but set as free space* so that next append operations will not require allocations up to the* number of bytes previously available. */ void sdsclear(sds s) { //在不釋放 SDS 的字符串空間的情況下,重置 SDS 所保存的字符串為空字符串。sdssetlen(s, 0); //設(shè)置長(zhǎng)度為0s[0] = '\0'; }/* Enlarge the free space at the end of the sds string so that the caller* is sure that after calling this function can overwrite up to addlen* bytes after the end of the string, plus one more byte for nul term.** Note: this does not change the *length* of the sds string as returned* by sdslen(), but only the free buffer space we have. *///對(duì)sds中buf的長(zhǎng)度進(jìn)行擴(kuò)展,確保在函數(shù)執(zhí)行之后,buf至少會(huì)有addlen+1長(zhǎng)度的空余空間(額外的1字節(jié)是為\0準(zhǔn)備的) sds sdsMakeRoomFor(sds s, size_t addlen) {//addlen是需要擴(kuò)展的長(zhǎng)度 void *sh, *newsh;size_t avail = sdsavail(s); //獲取s目前的空余空間長(zhǎng)度size_t len, newlen;char type, oldtype = s[-1] & SDS_TYPE_MASK; //取低3位,低3位存儲(chǔ)結(jié)構(gòu)體類(lèi)型。oldtype表示結(jié)構(gòu)體類(lèi)型int hdrlen;/* Return ASAP if there is enough space left. */if (avail >= addlen) return s;//s目前的空余空間已經(jīng)足夠,無(wú)須再進(jìn)行擴(kuò)展,直接返回len = sdslen(s);//獲取s目前已占用空間的長(zhǎng)度sh = (char*)s-sdsHdrSize(oldtype); //sh指向結(jié)構(gòu)體起始地址newlen = (len+addlen);// s 最少需要的長(zhǎng)度// 根據(jù)新長(zhǎng)度,為 s 分配新空間所需的大小if (newlen < SDS_MAX_PREALLOC)// 如果新長(zhǎng)度小于 SDS_MAX_PREALLOC // 那么為它分配兩倍于所需長(zhǎng)度的空間newlen *= 2;else// 否則,分配長(zhǎng)度為目前長(zhǎng)度加上 SDS_MAX_PREALLOCnewlen += SDS_MAX_PREALLOC;type = sdsReqType(newlen); //type可以指明存放長(zhǎng)度所需要的字節(jié)/* Don't use type 5: the user is appending to the string and type 5 is* not able to remember empty space, so sdsMakeRoomFor() must be called* at every appending operation. */if (type == SDS_TYPE_5) type = SDS_TYPE_8;hdrlen = sdsHdrSize(type);//hdrlen表示頭部所需要的長(zhǎng)度if (oldtype==type) {newsh = s_realloc(sh, hdrlen+newlen+1);if (newsh == NULL) return NULL;// 內(nèi)存不足,分配失敗,返回s = (char*)newsh+hdrlen;} else {/* Since the header size changes, need to move the string forward,* and can't use realloc */newsh = s_malloc(hdrlen+newlen+1);if (newsh == NULL) return NULL;memcpy((char*)newsh+hdrlen, s, len+1);s_free(sh);s = (char*)newsh+hdrlen;s[-1] = type;sdssetlen(s, len); //設(shè)置已經(jīng)使用了空間的長(zhǎng)度}sdssetalloc(s, newlen);//設(shè)置分配空間的長(zhǎng)度return s; }注意這里擴(kuò)展可都會(huì)改變結(jié)構(gòu)體的類(lèi)型。
/* Reallocate the sds string so that it has no free space at the end. The* contained string remains not altered, but next concatenation operations* will require a reallocation.** After the call, the passed sds string is no longer valid and all the* references must be substituted with the new pointer returned by the call. */ sds sdsRemoveFreeSpace(sds s) {//回收sds中的空閑空間,回收不會(huì)對(duì)sds中保存的字符串內(nèi)容做任何修改。void *sh, *newsh;char type, oldtype = s[-1] & SDS_TYPE_MASK; //oldtype表示結(jié)構(gòu)體類(lèi)型int hdrlen, oldhdrlen = sdsHdrSize(oldtype);//oldhdrlen表示結(jié)構(gòu)體頭部的長(zhǎng)度size_t len = sdslen(s); //返回sds實(shí)際保存的字符串的長(zhǎng)度size_t avail = sdsavail(s); //獲取剩余空間的長(zhǎng)度sh = (char*)s-oldhdrlen;/* Return ASAP if there is no space left. */if (avail == 0) return s;/* Check what would be the minimum SDS header that is just good enough to* fit this string. *///上面的oldtype是根據(jù)總長(zhǎng)算出來(lái)的typetype = sdsReqType(len);//根據(jù)sds有效串長(zhǎng)度 計(jì)算結(jié)構(gòu)體類(lèi)型hdrlen = sdsHdrSize(type);根據(jù)結(jié)構(gòu)體類(lèi)型決定sds頭部長(zhǎng)度/* If the type is the same, or at least a large enough type is still* required, we just realloc(), letting the allocator to do the copy* only if really needed. Otherwise if the change is huge, we manually* reallocate the string to use the different header type. */if (oldtype==type || type > SDS_TYPE_8) {//判斷結(jié)構(gòu)體類(lèi)型是否發(fā)生改變newsh = s_realloc(sh, oldhdrlen+len+1); //壓縮空間if (newsh == NULL) return NULL;s = (char*)newsh+oldhdrlen;} else {newsh = s_malloc(hdrlen+len+1);//進(jìn)行內(nèi)存重分配,讓 buf 的長(zhǎng)度僅僅足夠保存字符串內(nèi)容if (newsh == NULL) return NULL;memcpy((char*)newsh+hdrlen, s, len+1);s_free(sh);s = (char*)newsh+hdrlen;s[-1] = type;sdssetlen(s, len);}sdssetalloc(s, len);return s; }這里回收空間時(shí)也有可能改變結(jié)構(gòu)體的類(lèi)型。
/* Increment the sds length and decrements the left free space at the* end of the string according to 'incr'. Also set the null term* in the new end of the string.** This function is used in order to fix the string length after the* user calls sdsMakeRoomFor(), writes something after the end of* the current string, and finally needs to set the new length.** Note: it is possible to use a negative increment in order to* right-trim the string.** Usage example:** Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the* following schema, to cat bytes coming from the kernel to the end of an* sds string without copying into an intermediate buffer:** oldlen = sdslen(s);* s = sdsMakeRoomFor(s, BUFFER_SIZE);* nread = read(fd, s+oldlen, BUFFER_SIZE);* ... check for nread <= 0 and handle it ...* sdsIncrLen(s, nread);*///正數(shù)為增加,負(fù)數(shù)為縮減 void sdsIncrLen(sds s, ssize_t incr) {//根據(jù)incr參數(shù),增加sds的長(zhǎng)度,縮減空余空間,并將\0放到新字符串的尾端unsigned char flags = s[-1]; size_t len;switch(flags & SDS_TYPE_MASK) {case SDS_TYPE_5: {unsigned char *fp = ((unsigned char*)s)-1;unsigned char oldlen = SDS_TYPE_5_LEN(flags); //oldlen字符串的長(zhǎng)度assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));*fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS); //高5位保存長(zhǎng)度len = oldlen+incr; //修正len值break;}case SDS_TYPE_8: {SDS_HDR_VAR(8,s);assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));len = (sh->len += incr);break;}case SDS_TYPE_16: {SDS_HDR_VAR(16,s);assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));len = (sh->len += incr);break;}case SDS_TYPE_32: {SDS_HDR_VAR(32,s);assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));len = (sh->len += incr);break;}case SDS_TYPE_64: {SDS_HDR_VAR(64,s);assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));len = (sh->len += incr);break;}default: len = 0; /* Just to avoid compilation warnings. */}s[len] = '\0'; }注意這里時(shí)對(duì)有效字符串進(jìn)行操作,但是空間不能超過(guò)規(guī)定的最大值。
/* Identical sdsll2str(), but for unsigned long long type. */ int sdsull2str(char *s, unsigned long long v) {char *p, aux;size_t l;/* Generate the string representation, this method produces* an reversed string. */p = s;do {*p++ = '0'+(v%10);v /= 10;} while(v);/* Compute length and add null term. */l = p-s;*p = '\0';/* Reverse the string. */p--;while(s < p) {aux = *s;*s = *p;*p = aux;s++;p--;}return l; }long long 類(lèi)型轉(zhuǎn)換為字符串,逐個(gè)掃描,最后進(jìn)行反轉(zhuǎn)。
/* Like sdscatprintf() but gets va_list instead of being variadic. */ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {//將ap對(duì)應(yīng)的參數(shù)拼接成字符串,fmt表示匹配模式va_list cpy;char staticbuf[1024], *buf = staticbuf, *t;size_t buflen = strlen(fmt)*2;/* We try to start using a static buffer for speed.* If not possible we revert to heap allocation. */if (buflen > sizeof(staticbuf)) {buf = s_malloc(buflen);if (buf == NULL) return NULL;} else {buflen = sizeof(staticbuf);}/* Try with buffers two times bigger every time we fail to* fit the string in the current buffer size. */while(1) {buf[buflen-2] = '\0';va_copy(cpy,ap); //復(fù)制宏vsnprintf(buf, buflen, fmt, cpy);//fmt指定輸出格式的字符串,它決定了你需要提供的可變參數(shù)的類(lèi)型、個(gè)數(shù)和順序va_end(cpy);if (buf[buflen-2] != '\0') { //防止buf大小不夠一次讀不完if (buf != staticbuf) s_free(buf);buflen *= 2;buf = s_malloc(buflen);if (buf == NULL) return NULL;continue;}break;}/* Finally concat the obtained string to the SDS string and return it. */t = sdscat(s, buf);if (buf != staticbuf) s_free(buf);return t; }sdscatvprintf類(lèi)似字符串拼接功能。
/* This function is similar to sdscatprintf, but much faster as it does* not rely on sprintf() family functions implemented by the libc that* are often very slow. Moreover directly handling the sds string as* new data is concatenated provides a performance improvement.** However this function only handles an incompatible subset of printf-alike* format specifiers:** %s - C String* %S - SDS string* %i - signed int* %I - 64 bit signed integer (long long, int64_t)* %u - unsigned int* %U - 64 bit unsigned integer (unsigned long long, uint64_t)* %% - Verbatim "%" character.*/ sds sdscatfmt(sds s, char const *fmt, ...) {//格式化連接字符串size_t initlen = sdslen(s); //獲取串長(zhǎng)const char *f = fmt;long i;va_list ap;va_start(ap,fmt);f = fmt; /* Next format specifier byte to process. */i = initlen; /* Position of the next byte to write to dest str. */while(*f) {char next, *str;size_t l;long long num;unsigned long long unum;/* Make sure there is always space for at least 1 char. */if (sdsavail(s)==0) {s = sdsMakeRoomFor(s,1);}switch(*f) {case '%':next = *(f+1); //后移f++; //后移switch(next) {case 's':case 'S':str = va_arg(ap,char*); //獲取對(duì)應(yīng)元素printf("str =%s\n",str);l = (next == 's') ? strlen(str) : sdslen(str);if (sdsavail(s) < l) {s = sdsMakeRoomFor(s,l);}memcpy(s+i,str,l);sdsinclen(s,l); //修改串長(zhǎng)i += l;break;case 'i':case 'I':if (next == 'i')num = va_arg(ap,int);elsenum = va_arg(ap,long long);{char buf[SDS_LLSTR_SIZE];l = sdsll2str(buf,num);if (sdsavail(s) < l) {s = sdsMakeRoomFor(s,l);}memcpy(s+i,buf,l);sdsinclen(s,l);i += l;}break;case 'u':case 'U':if (next == 'u')unum = va_arg(ap,unsigned int);elseunum = va_arg(ap,unsigned long long);{char buf[SDS_LLSTR_SIZE];l = sdsull2str(buf,unum);if (sdsavail(s) < l) {s = sdsMakeRoomFor(s,l);}memcpy(s+i,buf,l);sdsinclen(s,l);i += l;}break;default: /* Handle %% and generally %<unknown>. */s[i++] = next;sdsinclen(s,1);break;}break;default:s[i++] = *f;sdsinclen(s,1);break;}f++;}va_end(ap);/* Add null-term */s[i] = '\0';return s; }此函數(shù)與sdscatprintf類(lèi)似,但速度要快得多。
sds sdstrim(sds s, const char *cset) {//對(duì)sds左右兩端進(jìn)行修剪,清除其中cset指定的所有字符,sdsstrim(xxyyabcyyxy, "xy") 將返回 "abc"char *start, *end, *sp, *ep;size_t len;sp = start = s;ep = end = s+sdslen(s)-1; //最后一個(gè)字符while(sp <= end && strchr(cset, *sp)) sp++; //strchr一個(gè)串中查找給定字符的第一個(gè)匹配之處while(ep > sp && strchr(cset, *ep)) ep--;len = (sp > ep) ? 0 : ((ep-sp)+1);if (s != sp) memmove(s, sp, len); //memmove字節(jié)拷貝s[len] = '\0';sdssetlen(s,len);return s; }該算法從左邊和右邊都遍歷一次達(dá)到兩邊裁剪的目的。
/* Turn the string into a smaller (or equal) string containing only the* substring specified by the 'start' and 'end' indexes.** start and end can be negative, where -1 means the last character of the* string, -2 the penultimate character, and so forth.** The interval is inclusive, so the start and end characters will be part* of the resulting string.** The string is modified in-place.** Example:** s = sdsnew("Hello World");* sdsrange(s,1,-1); => "ello World"*/ void sdsrange(sds s, ssize_t start, ssize_t end) { //按索引對(duì)截取sds字符串的其中一段,start和end都是閉區(qū)間(包含在內(nèi))size_t newlen, len = sdslen(s);if (len == 0) return;if (start < 0) {start = len+start;if (start < 0) start = 0;}if (end < 0) {end = len+end;if (end < 0) end = 0;}newlen = (start > end) ? 0 : (end-start)+1;if (newlen != 0) {if (start >= (ssize_t)len) {newlen = 0;} else if (end >= (ssize_t)len) {end = len-1;newlen = (start > end) ? 0 : (end-start)+1;}} else {start = 0;}if (start && newlen) memmove(s, s+start, newlen);s[newlen] = 0;sdssetlen(s,newlen); }注意start和end都可能為負(fù)值,其中-1表示末尾的字符,-2表示倒數(shù)第二個(gè)字符,依次類(lèi)推。
/* Split 's' with separator in 'sep'. An array* of sds strings is returned. *count will be set* by reference to the number of tokens returned.** On out of memory, zero length string, zero length* separator, NULL is returned.** Note that 'sep' is able to split a string using* a multi-character separator. For example* sdssplit("foo_-_bar","_-_"); will return two* elements "foo" and "bar".** This version of the function is binary-safe but* requires length arguments. sdssplit() is just the* same function but for zero-terminated strings.*///使用分隔符sep對(duì)s進(jìn)行分割,返回一個(gè) sds 字符串的數(shù)組。count 會(huì)被設(shè)置為返回?cái)?shù)組元素的數(shù)量。 sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count) {int elements = 0, slots = 5; long start = 0, j;sds *tokens; //字符串?dāng)?shù)組if (seplen < 1 || len < 0) return NULL;tokens = s_malloc(sizeof(sds)*slots); //sizeof(sds) = 8if (tokens == NULL) return NULL;if (len == 0) {*count = 0;return tokens;}for (j = 0; j < (len-(seplen-1)); j++) {/* make sure there is room for the next element and the final one */if (slots < elements+2) { //elements是下標(biāo)sds *newtokens;slots *= 2;newtokens = s_realloc(tokens,sizeof(sds)*slots);//tokens空間不夠重新分配內(nèi)存if (newtokens == NULL) goto cleanup;tokens = newtokens;}/* search the separator */if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) { //字符串比較tokens[elements] = sdsnewlen(s+start,j-start);if (tokens[elements] == NULL) goto cleanup;elements++;start = j+seplen; //前進(jìn)j = j+seplen-1; /* skip the separator */}}/* Add the final element. We are sure there is room in the tokens array. */tokens[elements] = sdsnewlen(s+start,len-start);if (tokens[elements] == NULL) goto cleanup;elements++;*count = elements;return tokens;cleanup:{int i;for (i = 0; i < elements; i++) sdsfree(tokens[i]);s_free(tokens);*count = 0;return NULL;} }遍歷字符串并和分隔符進(jìn)行比較,然后將字符串保存在字符數(shù)組中。
sds sdscatrepr(sds s, const char *p, size_t len) {//將長(zhǎng)度為 len 的字符串p以帶引號(hào)的格式,追加到給定sds的末尾s = sdscatlen(s,"\"",1);while(len--) {switch(*p) {case '\\':case '"':s = sdscatprintf(s,"\\%c",*p);break;case '\n': s = sdscatlen(s,"\\n",2); break; // \\表示轉(zhuǎn)義case '\r': s = sdscatlen(s,"\\r",2); break;case '\t': s = sdscatlen(s,"\\t",2); break;case '\a': s = sdscatlen(s,"\\a",2); break;case '\b': s = sdscatlen(s,"\\b",2); break;default:if (isprint(*p)) //判斷字符c是否為可打印字符s = sdscatprintf(s,"%c",*p);elses = sdscatprintf(s,"\\x%02x",(unsigned char)*p);break;}p++;}return sdscatlen(s,"\"",1); }遍歷字符串,然后格式化輸入。
總結(jié)
以上是生活随笔為你收集整理的redis源码之sds的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux可读可写为啥设置421
- 下一篇: va_list函数