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

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

       第二十四个。(就快写完注释了,结果一点保存全没了…什么奇葩。重写一遍吧:)该函数的作用和第二十五个函数一样,就是将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;
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值