0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

探索C语言入门基础之缓冲区

Android编程精选 来源:编程学习总站 作者:写代码的牛顿 2021-06-28 17:24 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

01

C标准库缓冲区探索

在计算机里缓存是一个很重要的概念,C标准库里大量使用了缓存,最为典型的就是标准输入和标准输出的缓存,关于C语言的输入和输出看这篇文章即可,利用好缓存可以大幅提高程序性能,首先我们看一下下面这段代码会输出什么?

#include 《stdio.h》 #include 《unistd.h》 int main() { printf(“Hello World!”); //往标准输出输出字符串 //程序停留在while循环里,程序退出会强制刷新缓冲区数据 while(1){ sleep(1); } return 0; }

我们在程序里调用printf函数打算在标准输出“Hello World!”,下面的while(1)循环是想让程序停在这里不退出程序,每次睡眠1s避免占用大量CPU资源,在Linux中包含unistd.h头文件才能使用sleep函数。现在我们编译以下看看会输出什么?

ce807804-d751-11eb-9e57-12bb97331649.png

我们看到,其实什么都没有输出。但是从程序上看,我们已经调用了printf函数往标准输出输出字符串,这就是缓存在起作用了。printf函数默认是行缓冲,当输出字符串里有 或者行缓冲区被填满或者手动调用fflush函数才会一次性将数据输出。现在你只要加上一条语句输出换行符,就能在标准输出输出字符串了。

printf(“ ”); //换行,默认标准输出会立即输出刷新缓冲区

或者我们手动调用fflush也可以强制刷新缓冲区,输出字符串。

fflush(stdout); //强制刷新标准输出缓冲区

往标准错误输出字符串的语句编译运行后会发生什么呢?

fprintf(stderr, “error information”); //往标准错误输出输出信息

fprintf函数将信息往第一个FILE指针类型参数输出,这里第一个参数我们传入stderr,编译运行后立即在控制台上输出字符串“error information”。标准错误输出和标准输出运行测试结果对比我们知道,调用fprintf函数往标准错误输出信息时不需要加字符‘ ’,也不需要强制刷新缓冲区也能立即输出信息。这是因为标准错误输出是无缓冲模式,写入什么数据就立即输出什么数据。

下面我们再看看输入代码

#include 《stdio.h》 int main() { char arr[100] = {0}; scanf(“%s”, arr); return 0; }

在这段代码里,程序运行后我们从标准输入输入数据,直到按下回车才将数据输入到数组arr里。在按下回车后,实际上刷新了输入缓冲区将数据一次性写入到数组arr里。

03

缓冲区的作用

在计算机里应用程序调用一个系统调用从用户态进去内核态再将结果回到用户态开销较大。如果我们调用printf函数,每次输出一个字符都要从用户态切换到内核态,那么连续输出多个字符开销成本将会非常大,这个时候缓存就起到非常大的作用了,输出的字符串先在应用程序里缓存起来,缓存到一定数量后再调用系统调用一次性将缓存数据输出到标准输出。

由于只调用了一次系统调用,比连续调用多个系统调用性能高上不少。在生活中我们也能感受到缓存带来的效率提升,打个比方你办公室有一个垃圾桶,楼下有倒垃圾的地点,如果扔一个垃圾到垃圾桶里我们就拿去倒掉,将会在办公室和楼下之间来回很多趟,浪费大量时间。如果将垃圾桶装满,再一次性拿到楼下倒掉,只需要跑一次就能把垃圾全都倒掉,节省了时间,提高了效率。

04

缓冲模式和使用方式

C语言里有行缓冲模式、全缓冲模式和无缓冲模式。

行缓冲模式:填满缓冲区或者有换行符‘ ’或者调用fflush函数强制刷新缓冲区会立即输出。

全缓冲模式:填满缓冲区或者调用fflush函数强制刷新缓冲区会立即输出。

无缓冲模式:写入什么数据就会立即输出什么数据,例如标准错误输出默认的缓冲模式。

下面我们用实际代码演示如何使用三种缓冲模式,设置缓冲模式会用到setvbuf函数,我们先来看看setvbuf函数声明。

/* Make STREAM use buffering mode MODE. If BUF is not NULL, use N bytes of it for buffering; else allocate an internal buffer N bytes long. */ extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf, int __modes, size_t __n) __THROW;

第一个参数是FILE类型指针,第二个参数是外部缓冲区指针,第三个参数是缓冲模式,第四个参数是缓冲大小,如果不使用外部缓冲区,函数内部将会调用malloc申请一块内存作为内部缓冲区。

形参mode提供了三个参数分别设置不同的缓冲区模式

_IONBF unbuffered _IOLBF line buffered _IOFBF fully buffered

无缓冲模式实例代码

#include 《stdio.h》 #include 《unistd.h》 int main() { setvbuf(stdout, NULL, _IONBF, 0); //标准输出设置为无缓冲,不使用外部缓冲区 printf(“Hello World!”); return 0; }

编译运行会立即输出

Hello World!

行缓冲模式实例代码

#include 《stdio.h》 #include 《unistd.h》 int main() { setvbuf(stdout, NULL, _IOLBF, 0); //标准输出设置为行缓冲模式,不使用外部缓冲区 printf(“how are you”); //不会立即输出字符串 fflush(stdout); //强制刷新缓冲区,立即输出字符串 return 0; }

编译运行后,由于调用了fflush会强制刷新数据到标准输出。

全缓冲模式实例代码

#include 《stdio.h》 #include 《unistd.h》 int main() { setvbuf(stdout, NULL, _IOFBF, 0); //标准输出设置为全缓冲模式,不使用外部缓冲区 printf(“Hello World!”); //不会立即输出 printf(“how are you”); //不会立即输出 printf(“ ”); while(1){ sleep(1); } return 0; }

编译运行后发现没有任何输出,现在我们在while循环前面加上下面这条语句,编译运行看看。

fflush(stdout); //强制刷新缓冲区

编译运行后立即输出了字符串!

同样的使用方式可以用于标准输入和标准错误输出,只需要把stdout缓存stdin或者stderr即可。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    7314

    浏览量

    93983
  • 计算机
    +关注

    关注

    19

    文章

    7764

    浏览量

    92682
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144617
  • 函数
    +关注

    关注

    3

    文章

    4406

    浏览量

    66839
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73151

原文标题:C语言入门基础之缓冲区

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    CW32L052串口的缓冲区机制

    默认缓冲区配置 CW32L052的UART模块支持硬件FIFO(通常为16字节),但HAL库或用户代码需手动管理接收缓冲区。若未显式分配足够大的软件缓冲区,可能导致数据溢出。 HAL库缓冲区
    发表于 11-24 06:40

    飞凌嵌入式ElfBoard-标准IO接口设置缓冲区

    1.setvbuf 用于以对文件的 stdio 缓冲区进行设置,譬如缓冲区缓冲模式、缓冲区的大小、起 始地址等。 1)头文件 #include 2)函数原型 int setvbuf
    发表于 11-14 09:02

    移植的lvgl,在运行的时候,缓冲区无法释放怎么解决?

    代码在运行的时候,只有lvgl线程用于刷新,另一个线程只有一个串口打印。 当运行一段时间后,发现,程序会在LVGl中,lv_refr.c这个库下面第625行代码, 在这一直判断,看介绍说是在等待释放缓冲区,求大神给个思路
    发表于 09-09 07:28

    USB缓冲区中的内容满了之后,是否有标志位进行反馈?

    USB缓冲区中的内容满了之后,是否有标志位进行反馈。
    发表于 07-17 07:13

    请问USB缓冲区取数据可以多次取吗?

    在使用USB软件获取数据是,下位机给我发送了13个32位数据到USB IN缓冲区,为什么我调用API函数想要第一次取1个32位数据,取完之后再取12位数据,程序会卡死。
    发表于 07-16 08:12

    解析RZ/N2L CANFD模块的缓冲区机制(2)

    在工业自动化、智能交通、机器人等领域,CANFD(CAN with Flexible Data-Rate)技术正逐步取代传统CAN,以适应更高的数据速率和更复杂的通信需求。本文将深入解析RZ/N2L CANFD模块的缓冲区机制,帮助工程师更高效地管理CAN消息,提高系统性能。
    的头像 发表于 05-19 14:13 1147次阅读
    解析RZ/N2L CANFD模块的<b class='flag-5'>缓冲区</b>机制(2)

    解析RZ/N2L CANFD模块的缓冲区机制(1)

    在工业自动化、智能交通、机器人等领域,CANFD(CAN with Flexible Data-Rate)技术正逐步取代传统CAN,以适应更高的数据速率和更复杂的通信需求。本文将深入解析RZ/N2L CANFD模块的缓冲区机制,帮助工程师更高效地管理CAN消息,提高系统性能。
    的头像 发表于 05-19 14:10 958次阅读
    解析RZ/N2L CANFD模块的<b class='flag-5'>缓冲区</b>机制(1)

    FX3 Socket缓冲区切换的最大时间是多少?

    FX3_Programmers_Manual 文档的第 10 章提到“每个缓冲区缓冲区切换开销为 550 - 900 ns”。 Getting_Started_with_EZ-USB_FX3 文档
    发表于 05-16 07:51

    在传输DMA通道中的所有缓冲区后,DMA标志(就绪和部分)被卡住了是怎么回事?

    是,旗帜最初的表现是正确的。 它们被配置为 ACTIVE HIGH 标志,初始值设为 LOW。 整个 DMA 通道默认使用两个 DMA 缓冲区。 传输开始时,第一个缓冲区被正确填满:部分标志(标志 b
    发表于 05-16 07:18

    求助,关于3014的缓冲区设置疑问求解

    rgb24 1080p@60fps是静态图像,dma缓冲区的配置即大小和数量分别为16kb,6,沿用的是yuy2的配置,但yuy2 1080p@60fps 是动态且不颠倒,是否可以认为是由于缓冲区
    发表于 05-06 13:42

    请问如何在Linux中使用帧缓冲区更新epdc显示?

    我正在使用带有 epdc 显示子卡 (IMXEBOOKDC5) 的 IMX8ULP EVK。使用 Linux 映像引导后,epdc 显示无法使用帧缓冲区进行更新。当检查显示 pmic 的电源使能引脚
    发表于 04-01 06:41

    FreeRTOS进阶使用之流缓冲区:高效处理字节流的秘密武器

    在嵌入式开发中,流缓冲区(Stream Buffer)是FreeRTOS中用于高效处理字节流数据传输的核心机制,尤其适合任务间或中断与任务间的连续数据传输场景(如串口通信、网络数据流等)。本文将深入
    发表于 03-24 11:37

    缓冲区溢出漏洞的原理、成因、类型及最佳防范实践(借助Perforce 的Klocwork/Hleix QAC等静态代码分析工具)

    本期来认识软件漏洞的“常客”——缓冲区溢出,C/C++开发者尤其要注意!全面了解该漏洞的成因、类型、常见示例,以及如何借助Klocwork、Helix QAC等SAST工具进行防护。
    的头像 发表于 03-04 16:39 1719次阅读
    <b class='flag-5'>缓冲区</b>溢出漏洞的原理、成因、类型及最佳防范实践(借助Perforce 的Klocwork/Hleix QAC等静态代码分析工具)

    RTOS的流缓冲区机制解析

    SAFERTOS中的流缓冲区(Stream buffer)机制,可以实现任务到任务或中断到任务之间的通信。字节流是由发送方写入缓冲区,接收方读取缓冲区数据。流缓冲区作为队列的轻量级级替
    的头像 发表于 02-14 11:33 974次阅读
    RTOS的流<b class='flag-5'>缓冲区</b>机制解析

    AMD Zen 4处理器悄然禁用循环缓冲区

    近日,AMD在更新BIOS后,对Zen 4架构的处理器进行了一项未公开说明的更改:禁用了循环缓冲区(Loop Buffer)功能。这一变化引发了业界和用户的广泛关注。 循环缓冲区作为CPU前端的一个
    的头像 发表于 12-11 13:46 831次阅读