[Redis][データ構造]sdsの学習
最近Redisのソースコードを勉強するのに多くの時間を費やすつもりで、主にhuangzの「redis設計と実現」といくつかのブログを参考にして、堅持して、この困難な任務を完成するように努力します.
このblogはsdsを読み終えたことを記録している.hとsds.c 2つのファイルの後のいくつかの疑問と総括.
1.struct sdshdr*sh=(void*)(s-(sizeof(struct sdshdr));ということになります.
まずS初期化のコードを見てみましょう.
Sは実際にはbufヘッダアドレスを指し、s−(sizeof(struct sdshdr)、すなわちアドレスは8バイト前方に移動し、sdsのstruct sdshdrヘッダアドレスを指す.
sdsは本質的にcharタイプの再構成であり,charに基づいて2つのint空間記憶文字列長と残りの空間を加えた.
2.なぜtypedef char*sdsなのか.typedef struct sdshdr*sdsではありません;?
sdsはcharを指すポインタであるが、sdshdrのstructを構築し、bufメモリ空間を指すことによって実現される.
sdsのこのような設計の利点は本の中で詳しく述べられている.
3.sdscatvprintf関数の学習:
このコードは可変パラメータの概念に関し,学習ノートを簡潔に記録する.
可変パラメータの手順は次のとおりです:1.まず関数にVAを定義しますパラメータを指すポインタであるLIST型の変数. 2.そしてVA_STARTマクロ初期化変数定義されたVA_LIST変数; 3.そしてVA_ARGは可変パラメータを返し、VA_ARGの2番目のパラメータは、あなたが返すパラメータのタイプです(関数に複数の可変パラメータがある場合は、VA_ARGを順次呼び出して各パラメータを取得します).4.最後にVA_ENDマクロで可変パラメータの取得を終了します.
各関数の具体的な役割:
va_list ap ;vaを定義するList変数ap va_start(ap,v) ;実行ap=(va_list)&v+INTSIZOF(v)は、apがパラメータvの後のパラメータのアドレス、すなわちapがスタックの最初の可変パラメータのアドレスを指す. va_arg(ap,t) , ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZOF(t))は,現在のapポインタが指す値を取り出し,apを次のパラメータに向ける.ap+=sizeof(tタイプ)は、apが次のパラメータのアドレスを指すようにします.次にap-sizeof(tタイプ)のtタイプ*ポインタを返します.これはスタック内の最初の可変パラメータのアドレスです.そして*でこのアドレスの内容を取得します. va_end(ap) ; va_をクリアlist ap.
上記の関数の機能と使い方を例に挙げて説明します.
ソースコードにはvsnprintf関数の使い方も含まれています.私も以下にまとめます.
関数プロトタイプ:int vsnprintf(char*str,size_t size,const char*format,va_list ap);関数の説明:可変パラメータを文字配列パラメータにフォーマット出力します:strが出力した配列、sizeがサイズを指定し、境界を越えないようにします.formatフォーマットパラメータ、ap可変パラメータリストの例:
4.sdssplitlen関数を勉強して、疑問があります
このblogはsdsを読み終えたことを記録している.hとsds.c 2つのファイルの後のいくつかの疑問と総括.
1.struct sdshdr*sh=(void*)(s-(sizeof(struct sdshdr));ということになります.
まずS初期化のコードを見てみましょう.
sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
// ,
// T = O(N)
if (init) {
// zmalloc
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
} else {
// zcalloc 0
sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
}
// ,
if (sh == NULL) return NULL;
//
sh->len = initlen;
// sds
sh->free = 0;
// , sdshdr buf
// T = O(N)
if (initlen && init)
memcpy(sh->buf, init, initlen);
// \0
sh->buf[initlen] = '\0';
// buf , sdshdr
return (char*)sh->buf;
}
Sは実際にはbufヘッダアドレスを指し、s−(sizeof(struct sdshdr)、すなわちアドレスは8バイト前方に移動し、sdsのstruct sdshdrヘッダアドレスを指す.
sdsは本質的にcharタイプの再構成であり,charに基づいて2つのint空間記憶文字列長と残りの空間を加えた.
2.なぜtypedef char*sdsなのか.typedef struct sdshdr*sdsではありません;?
sdsはcharを指すポインタであるが、sdshdrのstructを構築し、bufメモリ空間を指すことによって実現される.
sdsのこのような設計の利点は本の中で詳しく述べられている.
3.sdscatvprintf関数の学習:
/* s */
//s: ,fmt: s
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
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. */
// fmt 2 1024 staticbuf, , srarixbuf
if (buflen > sizeof(staticbuf)) {
buf = zmalloc(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';// 2 '\0'
va_copy(cpy,ap);
// T = O(N)
//
vsnprintf(buf, buflen, fmt, cpy);//buf: ,buflen: ,fmt: ,ap:
if (buf[buflen-2] != '\0') {// , 2
if (buf != staticbuf) zfree(buf);
buflen *= 2;
buf = zmalloc(buflen);
if (buf == NULL) return NULL;
continue;
}
break;
}
/* Finally concat the obtained string to the SDS string and return it. */
// sdscat buf s
t = sdscat(s, buf);
if (buf != staticbuf) zfree(buf);
return t;
}
このコードは可変パラメータの概念に関し,学習ノートを簡潔に記録する.
可変パラメータの手順は次のとおりです:1.まず関数にVAを定義しますパラメータを指すポインタであるLIST型の変数. 2.そしてVA_STARTマクロ初期化変数定義されたVA_LIST変数; 3.そしてVA_ARGは可変パラメータを返し、VA_ARGの2番目のパラメータは、あなたが返すパラメータのタイプです(関数に複数の可変パラメータがある場合は、VA_ARGを順次呼び出して各パラメータを取得します).4.最後にVA_ENDマクロで可変パラメータの取得を終了します.
各関数の具体的な役割:
va_list ap ;vaを定義するList変数ap va_start(ap,v) ;実行ap=(va_list)&v+INTSIZOF(v)は、apがパラメータvの後のパラメータのアドレス、すなわちapがスタックの最初の可変パラメータのアドレスを指す. va_arg(ap,t) , ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZOF(t))は,現在のapポインタが指す値を取り出し,apを次のパラメータに向ける.ap+=sizeof(tタイプ)は、apが次のパラメータのアドレスを指すようにします.次にap-sizeof(tタイプ)のtタイプ*ポインタを返します.これはスタック内の最初の可変パラメータのアドレスです.そして*でこのアドレスの内容を取得します. va_end(ap) ; va_をクリアlist ap.
上記の関数の機能と使い方を例に挙げて説明します.
/* */
#include//
#include
int AveInt(int v,...){
int ReturnValue=0;
int i=v;/v
va_list ap;// va_list
va_start(ap,v);// ,ap v
while (i>0) {
ReturnValue+=va_arg(ap,int);// ap , ap
i--;
}
va_end(ap);// va_list
return ReturnValue/=v;
}
int main(){
printf("%d\t",AveInt(2,2,3));
printf("%d\t",AveInt(4,2,4,6,8));
return 0;
}
ソースコードにはvsnprintf関数の使い方も含まれています.私も以下にまとめます.
関数プロトタイプ:int vsnprintf(char*str,size_t size,const char*format,va_list ap);関数の説明:可変パラメータを文字配列パラメータにフォーマット出力します:strが出力した配列、sizeがサイズを指定し、境界を越えないようにします.formatフォーマットパラメータ、ap可変パラメータリストの例:
#include
#include
void SYSTEM(const char *format,...){
char buff[4069];
va_list list;
va_start(list,format);//list format
vsnprintf(buff,4069,format,list);
va_end(list);
printf("%s
",buff);
}
int main(){
SYSTEM("%d %s",6,"abc");
return 0;
}
4.sdssplitlen関数を勉強して、疑問があります
if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0))
なぜ1文字と複数文字の比較に分けるのか.