printf 缓冲区原理 (你想知道的C语言 1.4)

2023-05-16

Q: 缓冲区究竟是什么概念?

A: 缓冲: 顾名思义, 表示可以酌情商量有回旋余地. 可以想象一种只能强制遵守且说一不二的情形,一种可以协商开发此消彼长的模式.

    区: 理解成可以协助存储/处理的物理位置,一般理解成内存。

    计算机科学的"缓冲区"概念可以说是到处都有, 这种模式的作用至少有两种:

    1 协助存储和内部处理;

    2 尽可能提高潜在的效率.

        就像是数学课代表统一把作业本交到办公室要比每个学生都跑一遍办公室更高效.    

 

Q: printf的缓冲区究竟在哪里?

A: printf隶属libc范畴, libc属于用户态, printf的缓冲区也可以理解成用户态分配的一段内存空间. 可以想象在每次调用printf的时候,内部都会根据分配的缓冲区状态进行判断, 如果没有必要真实输出,就先暂存,否则就按要求输出.

    如下是libc FILE结构体buffer的位置:

  对于缓冲区的操作,大体就是对于一块连续的memory写操作,每次都会记录position, 当position到达缓冲区最大或者有换行标志,就会强制刷新.

  缓冲区实例: printf 内部原理和实现 (你想知道的C语言 1.2)

  Apple libc源代码:  https://opensource.apple.com/source/Libc/Libc-1272.250.1/   printf.c

 

Q: 既然缓冲区是用户态, 我们如何dump缓冲区的数据?

A: 我们先尝试利用通过stdout找到对应FILE数据结构buffer指针,就可以dump具体数据了.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

void dump_stdout_buffer()
{
	FILE *fp;
	unsigned char *buf;
	int size;

	fp = stdout;
	buf = fp->_bf._base;
	size = fp->_bf._size;

	write(1, "stdout buffer:", strlen("stdout buffer:"));
	write(1, buf, size);
	write(1, "\n", 1);
}

int main(int argc, char *argv[])
{
	printf("cat");
	dump_stdout_buffer();
	printf("dog");
	dump_stdout_buffer();
	printf("\n");

	return 0;
}

代码: https://github.com/cxsjabc/basic/blob/dev/c/_topics/printf/dump_buffer.c

执行结果:

    

一开始, printf("cat")会把cat放入缓冲区, 后面放入dog, 最后catdog会一起输出.

当我们遇到printf没有输出的时候,可以从缓冲区角度考虑.

 

Q: printf缓冲区大小是多大?

A: 我们先不看libc实际设置的多少,采用江湖一直流传的手动构造缓冲区刷新的做法来反推缓冲区大小.

     https://blog.csdn.net/skyflying2012/article/details/10044035

     中心思想是不断打出一个字符, 每次间隔毫秒级别, 当第一次输出即缓冲区已经满了,此时记录输出的字符个数.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

void delay_ms(int miliseconds)
{
	int i;
	while(miliseconds) {
		for(i = 0; i < 100000; ++i) ;
		--miliseconds;
	}
}

void check_stdout_buf_size()
{
	while(1) {
		printf("a");
		delay_ms(1);
	}
}

int main(int argc, char *argv[])
{
	check_stdout_buf_size();

	return 0;
}

当屏幕第一次刷出一堆a之后停住的时候,按Ctrl + C终止程序,然后记录a的个数.

 实验得到的数据是: 4096.

 我们再用代码测试4096个字符输出将发生缓冲区满.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

void test_stdout_buf_size()
{
	int i;

	for(i = 0; i < 4096; ++i)
		printf("a");

	sleep(3);
	printf("b");
	sleep(10);
}

int main(int argc, char *argv[])
{
	test_stdout_buf_size();

	return 0;
}

实验结果表明: 在4096个字符a输出后,间隔13秒左右才会输出剩下的b, 即证缓冲区大小为4096!

 

作者:     陈曦
环境:     MacOS 10.14.5
         Apple LLVM version 10.0.1 (clang-1001.0.46.4)
         Target: x86_64-apple-darwin18.6.0
 
转载请注明出处

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

printf 缓冲区原理 (你想知道的C语言 1.4) 的相关文章

  • 上电自动开机

    上电开机启动是指电脑主机在UPS恢复供电时可以自动开机 该功能必须要求电脑主板型号支持 xff0c 进入电脑的BIOS进行设置使用 不同型号的电脑的BIOS设置会有区别 xff0c 以下仅做参考 xff1a 第一步 xff1a 开机进入BI
  • Linux网络编程【TCP】

    文章目录 TCP特点TCP中CS架构TCP状态转换相关操作函数recv函数send函数 TCP特点 TCP是一种面向广域网的通信协议 xff0c 目的是在跨越多个网络通信时 xff0c 为两个通信端点之间提供一条具有下列特点的通信方式 xf
  • 博客资源整理

    文章目录 STLLinux基础命令linux系统编程Linux网络编程Docker容器技术数据库第三方库的使用Linux编程WebQt STL 基础概念 容器 duque stack map set vector 算法 查找算法 排序算法
  • Qt编译Mysql驱动

    1找到源码 2点击编译会看到报错 1解决方案 下载相关文件 也可以私信发给你 2打开配置文件添加下面的信息 相关文件下载 3点击编译 弹出的框直接关掉就行 4在安装qt的根目录下会生成如下目录 5 找到下面的库 6 将上面的库拷贝到如下目录
  • C++中的异常语法

    文章目录 概述异常的关键子自定义异常使用栈解旋异常的接口声明异常变量的生命周期C 43 43 标准异常库 概述 C语言的异常缺陷在于返回值只有一个 xff0c 可能出现二义性 xff0c 没有统一的标准 C 43 43 中的异常必须有处理
  • 处理鼠标连续点击的问题

    处理鼠标连续点击的问题 span class token comment 上次点击时间点 span DWORD m tmClick span class token punctuation span span class token com
  • FLOPS和FLOPs、GFLOPs区别与计算

    参考FLOPS和FLOPs GFLOPs区别与计算
  • VS远程调试

    文章目录 VS远程调试本地和虚拟机调试准备工作 xff1a 需要注意的几个地方 xff1a VS远程调试 在编程中由于环境 版本等各种原因 xff0c 我们需要模拟出来各种环境来跑不同的版本测试 本地和虚拟机调试 准备工作 xff1a 以V
  • AUTOSAR基础篇之CanNM

    前言 首先 xff0c 问大家几个问题 xff0c 你清楚 xff1a 为什么要引入网络管理呢 xff1f 上电同时启动 xff0c 下电同时关闭 xff0c 它不香吗 xff1f 你知道车上的ECU节点可以分为哪几种类型吗 xff1f 汽
  • CANoe应用案例之DoIP通信

    随着ECU功能和存储容量的不断提高 xff0c 主机厂对于ECU诊断和刷写有了更高的要求 由于带宽的限制 xff0c 传统的汽车总线 xff08 如CAN总线 xff09 存在刷写时间过长的缺点 xff0c 大大降低了生产和维修效率 DoI
  • TRACE32——常用操作

    TRACE 32常用操作 TRACE32软件打开后 xff0c 连上硬件环境 xff0c 我们就可以开始尝试和芯片建立连接 xff0c 并进行基本的调试操作 第一步 xff1a 确认目标板是否上电 第二步 xff1a 打开System Se
  • TRACE32——基于SNOOPer的变量记录

    TRACE32 基于SNOOPer的变量记录 在我们日常调试工作中 xff0c 经常会遇到一种场景 xff1a 对于某些变量或者内存的值 xff0c 希望对其进行监控 当这些变量发生写或者读的时候 xff0c 将这些操作记录下来 xff0c
  • TRACE32——内存填充测试Data.Pattern

    TRACE32 内存填充测试Data Pattern Data Pattern 命令可以用于对内存 xff08 SRAM DDR Flash等 xff09 写入随机值 xff0c 以快速地测试内存是否可以正确读写 命令格式 xff1a 示
  • STM32使用printf重定向

    最近用STM32CubeMX创建了一个demo工程 xff0c 在调试过程中 xff0c printf打印功能一直不能正常打印 xff0c 检查工程中也已将fputc函数进行了实现 奇怪的是用JTAG进行调试时打印恢复了正常 最后发现问题的
  • repo的安装和使用

    前言 Android 采用 Gerrit 提供代码评审服务 xff0c 并且开发了一个客户端工具 repo xff0c 实现多仓库管理 Git 的开发者对服务端的 Git 源码做了扩展 xff0c 使得基于 Git xff08 cgit x
  • repo sync之后不能自动 rebase 的定位

    背景 最近在使用repo sync同步代码时老是报告 xff1a branch xxx is published but not merged and is now 1 commits behind 我之前是由推送过一笔提交 xff0c 但
  • git取指定日期log问题

    库上版本有一个重要bug xff0c 使用了如下命令取一个版本 xff1a repo forall c 39 commitID 61 96 git log before 34 2022 12 09 00 00 00 34 1 pretty
  • ROS读取激光雷达点云数据(RS-Lidar为例)

    一 准备工作 xff1a 1 安装ROS xff08 含有rviz xff09 xff1b 2 安装pcl ros pcl xff08 Point Cloud Library xff09 ros 是ROS中点云和3D几何处理的接口和工具 如
  • 标准预定义的宏

    标准预定义宏是由相关的语言标准规定的 xff0c 所以它们可以在所有执行这些标准的编译器中使用 旧的编译器可能不会提供所有这些宏 它们的名字都以双下划线开头 FILE 这个宏扩展为当前输入文件的名称 xff0c 以 C 字符串常数的形式 这
  • Realsense L515使用

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 前言一 主要参考二 基本情况 xff08 一 xff09 ubuntu和ROS情况 xff08 二 xff09 主要步骤 总结

随机推荐