[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;}
先记录到这。第二十六个函数内容有点多,放下次。:)
阅读全文
0 0
- [SDS阅读理解/8]源码中的函数/5
- [SDS阅读理解/5]源码中的函数/2
- [SDS阅读理解/3]源码中的函数/0
- [SDS阅读理解/4]源码中的函数/1
- [SDS阅读理解/6]源码中的函数/3
- [SDS阅读理解/7]源码中的函数/4
- [SDS阅读理解/9]源码中的函数/6
- [SDS阅读理解/1]源码中的宏
- [SDS阅读理解/2]源码中的数据结构
- [SDS阅读理解/0]前言
- redis源码阅读笔记(一):sds
- Redis源码阅读笔记—sds
- Redis源码阅读笔记(1)-- 动态字符串sds
- ThinkPHP源码阅读理解
- jQuery源码阅读(九)---ready函数理解
- redis 源码笔记--sds
- Redis源码解析【SDS】
- HashMap源码阅读与理解
- 上传文件乱码问题
- 背包习题集
- HDU6000 Wash 二分+贪心
- HDOJ2124 Repair the Wall(类似背包问题)
- 【python数据挖掘课程】十八.线性回归及多项式回归分析四个案例分享
- [SDS阅读理解/8]源码中的函数/5
- 1046. Shortest Distance (20) 单环图的求路径性质
- ActiveMQ(5)-基于ZooKeeper的HA方案
- 集群与分布式的区别
- Apache设置二级域名
- 把自己以前零散的技术学习都移植过来吧,这里编辑文章感觉还不错
- UIImageView
- C语言基础之数组
- 2017年11月25日,技术笔记整理