前言
在最开始的 cmd 编程中, 我们会使用到的最常见的输出, 包括一些时候调试的时候 我们最常使用到的函数 那肯定是 printf 了
我们这里来调试一下 这个 printf
还有一个原因是 之前在调试 malloc 的时候, malloc 虚拟内存分配的调试(1) 可以发现, 不仅仅是在 malloc 的时候调用了 malloc, 在 printf 的时候也调用了 malloc
然后 我们这里来看一下 具体的情况, 以及一些 抽象的理解映射到 代码上面怎么处理的
也可以参考一下 printf 命令 二者有一些相似之处, 不过一个是 可执行程序, 一个是 glibc 提供的库函数
测试用例
同样是基于 这个最简单的 case, 不过这里 我们关注的是 printf
root@ubuntu:~/ClionWorkStations/HelloWorld# cat Test01Sum.c
#include "stdio.h"
int main(int argc, char** argv) {
int x = 2;
int y = 3;
int z = x + y;
char *p1 = (char *)malloc(20);
char *p2 = (char *)malloc(20);
*p1 = '1';
*(p1+1) = '2';
free(p2);
void *p3 = realloc(p1, 10);
printf("p1 : 0x%x - 0x%x \n", p1, p2);
printf("p3 : 0x%x - 0x%x \n", p3, p3);
}
printf 的核心流程
看一下 我们这里断点的位置, 确实是在 main 中的第一个输出的位置
大致的流程是 找到第一个占位符的位置, 然后输出 第一个占位符之前的常量字符串 到 s
然后之后 从第一个占位符开始 循环处理每一个 占位符
处理当前占位符, 结合 占位符指定的格式 分为数字类输出 和 字符串类输出, 分别在 process_arg, process_string_arg 中输出
这两个宏中 做的不同格式的 格式化的相关操作
并且 查找下一个占位符, 输出两个占位符之间的常量字符串, 如果没有下一个占位符, 输出剩余的常量字符串到 s
我们这里是按照 十六进制 输出 p1地址, 因此 走的是 process_arg, 处理之前 s 中内容如下
process_arg 宏处理完成之后, s 中的内容增加了作为参数的 p1 的地址的 十六进制 表示
查找下一个 占位符, 输出当前占位符 和 下一个 占位符之间的 常量字符串
其实 和 printf 程序 还是有一些 相似之处的
printf 的输出
如果当前 buf 是 LINE_BUF, 并且 正在输出
则当前 待输出数据中包含 回车 的时候, 必须要 输出到设备, 输出内容到 回车 的位置
然后 将带输出字符串 拷贝到 buf 中
如果 待输出字符串大小超过了 缓冲区间大小, 或者是 行缓冲 碰到了 换行, 则要求输出内容到设备
然后 如果还剩余待输出内容, 则输出内容到 缓冲/设备
然后 如果还剩余待输出内容, 则输出内容到 缓冲/设备
判断根据 blockSize 对齐之后需要输出多少字节的内容到 缓冲/设备, 然后递归调用 new_do_write 来输出 (todo/block_size) 个blockSize 的内容到 缓冲/设备
然后 将剩余的待输出数据 输出到 缓冲
比如 todo 为 248, blockSize 为 100, 则递归调用 new_do_write 输出 200 个字节到 缓冲/设备
剩余的 48 字节通过下面的 IO_default_xsputn 输出到 缓冲
printf 的持久化输出是基于系统调用 write 来实现的
将缓冲的数据 通过 write 输出到 fp 中
在内核层面, 看到这一次 write 如下[这里调整了应用程序, 输出 和 上下文输出不太一样, 不过意思一样]
这里 有空我们, 展开来讲讲, 这里的 tty 的输出
printf 分配的缓冲区间
这里的 _IO_BUFSIZ 的宏为 8192, 下面的 st.st_blksize 为 1024
优先取的后者, 因此 printf 输出 buf 的大小为 1024 字节
并且 上面, 如果是 字符设备, 还将 buf 增加了 行缓冲 的标记
然后 这里分配的 缓冲区间, 也是来自于 malloc, 因此 分配的区间的地址信息, 可以根据 p1, p2 的地址 推导出来, 你可以试试
一个简单地测试方式是 malloc 一个 p3, 然后 观察 p2, p3 之间的空间, 这块空间就是 printf 的缓冲区间
修改 用例如下
root@ubuntu:~/ClionWorkStations/HelloWorld# cat Test01Sum.c
#include "stdio.h"
int main(int argc, char** argv) {
int x = 2;
int y = 3;
int z = x + y;
char *p1 = (char *)malloc(20);
char *p2 = (char *)malloc(20);
*p1 = '1';
*(p1+1) = '2';
free(p2);
printf("p1 : 0x%x - 0x%x \n", p1, p2);
void *p3 = malloc(10);
printf("p1 : 0x%x - 0x%x \n", p1, p2);
printf("p3 : 0x%x - 0x%x \n", p3, p3);
}
输出如下, 可以推导出 printf 的 buf 地址为 0x602050, 大小为 (0x602440 - 0x602030) = 0x410 = 1040
计算方式为 ALIGN_UP((1024 + 8), 16) = 1040
地址为 p2 之后的空间, p3 之前的空间 文章来源:https://www.toymoban.com/news/detail-429519.html
p1 : 0x602010 - 0x602030
p1 : 0x602010 - 0x602030
p3 : 0x602440 - 0x602440
完文章来源地址https://www.toymoban.com/news/detail-429519.html
到了这里,关于20 printf 的调试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!