[SDS阅读理解/8]源码中的函数/5

来源:互联网 发布:multiselect.zh cn.js 编辑:程序博客网 时间:2024/05/22 04:58

空了一段时间…不过还是得完成记录

       第二十四个。(就快写完注释了,结果一点保存全没了…什么奇葩。重写一遍吧:)该函数的作用和第二十五个函数一样,就是将fmt这串字符格式化后保存到s中并返回它的地址。我们一般直接使用第二十五个函数,这个函数是给第二十五个函数调用的。主要涉及到两个知识点-变参函数和va_list这个参数(来自<stdarg.h>),网上搜索相关内容看下,再用下sprintf()这个函数,会比较好理解下面的代码。

// 作者注释/* Like sdscatprintf() but gets va_list instead of being variadic. */// 返回的地址和s变量的地址一样的,这样做是为了实现链式操作// 比如我们可以将这个函数作为参数传入另一个函数中sds sdscatvprintf(sds s, const char *fmt, va_list ap) {    // va_list这个参数具体原理我..也不是很清楚    // 不过用法都差不多,如果我们自己写变参函数,先照着这样写    va_list cpy;    char staticbuf[1024], *buf = staticbuf, *t;    // 计算需要格式化的字符串的个数    // 注意fmt里头可能含有'%d'这样的格式,它占两个字符    // *2是为了一次申请更多的空间,避免以后空间不够又重新申请,提高效率    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)) {        // 需要格式化的字符串的空间大于staticbuf的空间        // buf本来指向staticbuf,现在指向新申请的空间        buf = s_malloc(buflen);        if (buf == NULL) return NULL;    } else {        // staticbuf的空间足够大        // buflen赋值为staticbuf的大小,也就是1024        buflen = sizeof(staticbuf);    }    /* Try with buffers two times bigger every time we fail to     * fit the string in the current buffer size. */    // 下面的循环做了两件事-格式化fmt并保存到buf中    // 如果buf的空间不够大,重新为buf申请空间    // 这不是死循环,因为后面有个break    while(1) {        // 将buf指向的地址的倒数第3个字符赋值为空        // 这样做是为了判断buf的空间够不够大        buf[buflen-2] = '\0';        // 下面的函数将ap参数的内容拷贝到cpy中,先不用纠结为啥样这样做        // 假装这里就是得这样做:)        va_copy(cpy,ap);        // 下面这个函数是标准库中的函数        // 它的作用是将buflen个格式化后的fmt字符保存到buf中        // 作者的函数作用和这个差不多,为什么还要重写一个        // 因为作者的函数还做了其它事        vsnprintf(buf, buflen, fmt, cpy);        // 格式化完成后记得调用下面这个函数        va_end(cpy);        // 下面的代码块就是做的其它事了        // 前面buf[buflen-2]赋值为空了,经过上面的格式化保存后        // 如果buf的空间比需要保存的字符串小,那它就不是空了        if (buf[buflen-2] != '\0') {            // 如果不为空,说明buf空间不够            // 如果buf不是指向staticbuf的地址,那就是指向了堆中申请的空间            // 但是这里空间又不够,就先释放掉这段空间            if (buf != staticbuf) s_free(buf);            // 需要重新申请的空间扩大为之前的两倍            buflen *= 2;            // 在堆中申请空间            buf = s_malloc(buflen);            // 申请失败,返回空            if (buf == NULL) return NULL;            // 申请成功,重新执行整个循环            // 为什么要重新执行一遍?当然是为了将格式化后的字符串保存到buf中            // 如果buf[buflen-2]为空,说明buf的空间够了            // 就不会执行整个if语句块了,并跳出while循环            continue;        }        break;    }    /* Finally concat the obtained string to the SDS string and return it. */    // 经过上面的代码,已经成功将字符串格式化并保存到buf中了    // t是一个空指针,会指向下面这个函数申请的地址    // 函数原理前面章节有讲,作用是将buf这串字符合并到s后面    // t指向的地址就是s指向的地址    t = sdscat(s, buf);    // 已经将buf的内容保存到s中了    // 如果buf指向的是堆中空间,释放它    if (buf != staticbuf) s_free(buf);    return t;}

       第二十五个。(终于注释完了第二十四个:)其实之前是接着记录的,到第二十四个的时候,看了下不太懂,就空了一段时间了。

// 作者注释/* Append to the sds string 's' a string obtained using printf-alike format * specifier. * * After the call, the modified sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. * * Example: * * s = sdsnew("Sum is: "); * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b). * * Often you need to create a string from scratch with the printf-alike * format. When this is the need, just use sdsempty() as the target string: * * s = sdscatprintf(sdsempty(), "... your format ...", args); */// 该函数作用和第二十四个一样// 用法'sds s = sdscatprintf(sdsempty(), "abc%d", 1);'// 那么'(s == "abc1")',注意第一个参数不是传入s,而是sdsempty()// 因为第一个参数的空间地址必须合法才能格式化成功sds sdscatprintf(sds s, const char *fmt, ...) {    // 假装这里必须声明一个这样的变量:)    va_list ap;    // 作者这里为啥不直接这样声明sds t;    char *t;    // va_start()和va_end()是一对    // 用来处理变参    va_start(ap, fmt);    // 调用第二十四个函数    t = sdscatvprintf(s,fmt,ap);    va_end(ap);    // 格式化成功    return t;}

       先记录到这。第二十六个函数内容有点多,放下次。:)

原创粉丝点击