缓冲区

admin 2025年1月6日11:32:30评论2 views字数 2180阅读7分16秒阅读模式
缓冲区

缓冲区

之前介绍了IO,当我们新建一个file结构体的时候来看看会怎么加入链表

首先我们建立一个1.txt文件,里面随便写入内容echo "liyou">>1.txt

然后编译生成可执行程序,源代码如下:

#include<stdio.h>

intmain()

{

   FILE *fp;

charbuff[255];

chara[]="12345";

   fp = fopen("./1.txt", "r");

fscanf(fp, "%s", buff);

printf("1 : %sn", buff );

fgets(buff, 255, (FILE*)fp);

printf("2: %sn", buff );

fclose(fp);

}

这里面使用到了FILE结构体指针,使用fopen打开文件,这时候就会触发init初始化操作,从而进入_IO_list_all链表

缓冲区

缓冲区

这里加入链表的方式是在_IO_list_all之后加入(_IO_2_1_stderr_之前

缓冲区

并且使用open函数的话建立的链表是在堆地址上开辟的,也就是说open一定会调用内存分配的函数,会触发__malloc_hook,当fclose之后会释放内存

缓冲区

也就是说一定会触发__free_hook

并且触发解链_IO_list_all之后fp指针如果不手动清空的话会出现fp和_IO_list_all都指向同一块内存位置(UAF)

缓冲区

首先什么是缓冲区,为什么需要缓冲区

在计算机里缓存是一个很重要的概念,C标准库里大量使用了缓存,最为典型的就是标准输入和标准输出的缓存,利用好缓存可以大幅提高程序性能。

我们来看看菜鸟教程里面的描述:

C语言setbuf()函数:把缓冲区与流相关联
头文件:

1
#include <stdio.h>

函数setbuf()用于将指定缓冲区与特定的文件流相关联,实现操作缓冲区时直接操作文件流的功能。其原型如下:

1
void setbuf(FILE * stream, char * buf);

【参数】stream为文件流指针,buf为缓冲区的起始地址。

如果参数buf 为NULL 指针,则为无缓冲,setbuf()相当于调用setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZE)。

说明:在打开文件流后,读取内容之前,可以调用setbuf()来设置文件流的缓冲区(而且必须是这样)。

C语言setvbuf()函数

描述

C 库函数 int setvbuf(FILE *stream, char *buffer, int mode, size_t size) 定义流 stream 应如何缓冲。

声明

下面是 setvbuf() 函数的声明。

int setvbuf(FILE *stream,char*buffer,int mode,size_t size)

参数

  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。

  • buffer -- 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。

  • mode -- 这指定了文件缓冲的模式:

模式 描述
_IOFBF 全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。
_IOLBF 行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。
_IONBF 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。
  • size --这是缓冲的大小,以字节为单位。

返回值

如果成功,则该函数返回 0,否则返回非零值。

我们来看一个例子:

#include<stdio.h>

#include<unistd.h>

intmain()

{printf("liyou66666");

while(1){

sleep(1);

   }

return0;}

在Linux中包含unistd.h头文件才能使用sleep函数

运行后发现

缓冲区

输出的结果是空的,程序一致在死循环,为什么没有输出结果呢?正常情况在进入while的时候就已经执行了printf,这里为什么没有输出呢?这就涉及到缓冲区的问题了

printf函数默认是行缓冲,当输出字符串里有n或者行缓冲区被填满或者手动调用fflush函数才会一次性将数据输出。

所以这里我们想输出内容的话有两种办法,第一就是执行

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

第二就是

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

这个stdout是什么呢?

在stdout.c中我们看到stdout和stderr定义如下:

FILE *stdout = (FILE *) &_IO_2_1_stdout_;

stdout和文件描述符1绑定,需要注意的是标准错误输出是无缓冲模式,写入什么数据就立即输出什么数据

缓冲区的作用

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

原文始发于微信公众号(由由学习吧):缓冲区

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月6日11:32:30
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   缓冲区https://cn-sec.com/archives/1218263.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息