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

    文章

    6909

    浏览量

    88849
  • 计算机
    +关注

    关注

    19

    文章

    7430

    浏览量

    87731
  • C语言
    +关注

    关注

    180

    文章

    7601

    浏览量

    136248
  • 函数
    +关注

    关注

    3

    文章

    4308

    浏览量

    62444
  • 代码
    +关注

    关注

    30

    文章

    4753

    浏览量

    68365

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

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

收藏 人收藏

    评论

    相关推荐

    分享一个嵌入式通用FIFO环形缓冲区实现库

    开源项目ringbuff ,是一款通用FIFO环形缓冲区实现的开源库,作者MaJerle,遵循 MIT 开源许可协议。
    的头像 发表于 10-23 16:20 272次阅读
    分享一个嵌入式通用FIFO环形<b class='flag-5'>缓冲区</b>实现库

    内存缓冲区和内存的关系

    内存缓冲区和内存之间的关系是计算机体系结构中一个至关重要的方面,它们共同协作以提高数据处理的效率和系统的整体性能。
    的头像 发表于 09-10 14:38 435次阅读

    单片机中的几种环形缓冲区的分析和实现

    单片机中的几种环形缓冲区的分析和实现一、简介环形缓冲区(RingBuffer)是一种高效的使用内存的方法,它将一段固定长度的内存看成一个环形结构,用于存储数据,能够避免使用动态申请内存导致的内存碎片
    的头像 发表于 08-14 08:39 717次阅读
    单片机中的几种环形<b class='flag-5'>缓冲区</b>的分析和实现

    ESP8266有双缓冲区吗?

    我想实时传输一些信号的测量数据。信号的采样周期为 1 ms。我想每 500 毫秒发送 2048 字节(一个数据包)。ESP8266有双缓冲区(2x 2048字节)吗?其想法是计数填充一个缓冲区(周期
    发表于 07-16 07:29

    创建DMA通道时,能否将DMA缓冲区的大小指定为8字节,并将DMA缓冲区的编号指定为1?

    创建 DMA 通道时,能否将 DMA 缓冲区的大小指定为 8 字节,并将 DMA 缓冲区的编号指定为 1?
    发表于 05-31 07:46

    stm32野火开发板上做USB通信,PC端USB的缓冲区和串口缓冲区的大小是多少?

    stm32野火开发板上做USB通信,用的CDC虚拟串口。 stm32端将ADC采集的数据通过USB传给电脑,传输速率理论上是12Mbps,上位机是从PC端的串口缓冲区拿数据,用C#编写的上位机将
    发表于 05-17 14:02

    具有八进制反相缓冲区的扫描测试设备数据表

    电子发烧友网站提供《具有八进制反相缓冲区的扫描测试设备数据表.pdf》资料免费下载
    发表于 05-17 09:58 0次下载
    具有八进制反相<b class='flag-5'>缓冲区</b>的扫描测试设备数据表

    这个CRC计算单元是如何基于固定的生成多项式(0x4C11DB7)来获取给定数据缓冲区的CRC码的?

    这个CRC计算单元是如何基于固定的生成多项式(0x4C11DB7)来获取给定数据缓冲区的CRC码的?
    的头像 发表于 05-16 16:06 740次阅读

    实现稳健的微控制器到FPGA SPI接口: 双缓冲区

    在介绍双缓冲器之前,我们将简要探讨Verilog 脉宽调制器 (PWM) 的工作原理。这一点很重要,因为双缓冲区最好被看作是硬件模块 (如 PWM) 的可寻址接口。
    的头像 发表于 05-16 09:36 646次阅读
    实现稳健的微控制器到FPGA SPI接口: 双<b class='flag-5'>缓冲区</b>!

    Stm32采用环形缓冲区接收rk3588的数据代码

    Stm32采用环形缓冲区接收rk3588的数据代码
    的头像 发表于 05-15 10:10 525次阅读

    交换机与路由器缓冲区:寻找完美大小

    *本文系SDNLAB编译自瞻博网络技术专家兼高级工程总监Sharada Yeluri领英 在路由器和交换机中,缓冲区至关重要,可以防止网络拥塞期间的数据丢失。缓冲区到底要多大?这个问题在
    的头像 发表于 04-11 16:56 1105次阅读
    交换机与路由器<b class='flag-5'>缓冲区</b>:寻找完美大小

    交换芯片缓冲区大小是什么

    交换芯片缓冲区大小并不一定是固定的。缓冲区的设计和实现会根据芯片的具体型号、规格以及应用场景的不同而有所差异。一些交换芯片可能具有固定大小的缓冲区,以满足特定的性能需求或成本限制。然而,随着技术
    的头像 发表于 03-18 14:42 552次阅读

    使用UART FIFO缓冲区时,缓冲区中的数据有时会损坏的原因?

    我在使用 UART FIFO 缓冲区时遇到了以下问题。 问题描述: 当通过两个 UART 通道使用完整的 UART FIFO 缓冲区并通过两个通道进行通信时,缓冲区中的数据有时会损坏,例如,UART
    发表于 03-06 06:59

    西门子博诊断缓冲区的使用方法

    可从在线和诊断视图中“诊断”文件夹的“诊断缓冲区”组中读出 CPU 的诊断缓冲区
    的头像 发表于 12-11 10:24 3998次阅读
    西门子博诊断<b class='flag-5'>缓冲区</b>的使用方法

    使用malloc建立缓冲区时出现错误怎么解决?

    ,我不知道现在这个已知系统的中断频率,所以我做了一个偷懒的想法,先把输入数据3秒的数据放在自建的缓冲区,再将这个数据处理后再输出,延时大概3s数据的时间,现在但是使用malloc建立缓冲区时出现错误,请问,怎么拯救?
    发表于 11-30 07:39