ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C语言标准库深入浅出

2022-01-07 13:31:56  阅读:220  来源: 互联网

标签:深入浅出 接口 C语言 标准 IO 使用 缓冲区 低级


  名为 stdio.h 的标准库头文件,我们便可以快捷地为 C 程序添加读取用户键盘输入、输出内容到控制台,乃至读写文件等一系列常规的 IO 功能。

  今天,我们来说一说C 语言中的标准 IO 模型,以及它背后的一些原理。

  快速回顾 IO 接口的使用方法

  首先,让我们通过下面这段代码来快速回顾,应该如何在 C 语言中使用这些由标准库提供的 IO 接口。

  这里,在 main 函数内部,我们通过多种不同的方式,让程序与进程预设的 IO 流以及我们自行打开的 IO 流产生了交互。

  其中,代码第 3 行,通过 printf 函数,我们可以将指定的文本传送至标准输出流(stdout)中。紧接着,借助代码第 4 行的 fopen 函数,我们得以在当前目录下打开名为 “temp.txt” 的文件,并将其与一个特定的文件 IO 流相关联。而当文件打开失败时,通过代码第 12 行的 perror 函数,我们能够将特定的错误信息传送到标准错误流(stderr)。最后,在代码的第 7 行,scanf 函数的调用可以让我们从标准输入(stdin)流中,读取从外部环境输入的信息。

  IO 接口的不同级别

  通常来说,IO 接口可以被分为不同层次。其中,C 语言提供的 IO 接口属于“标准 IO”的范畴。与其相对的,是名为“低级 IO”的另一套编程模型。顾名思义,低级 IO 会使用与具体操作系统相关的一系列底层接口来提供相应的 IO 能力,比如常用于 Unix 与类 Unix 操作系统上的 POSIX 接口标准。如果我们将上面的示例程序完全用该标准进行重写,将会得到如下所示的代码:

  可以看到,在使用低级 IO 接口进行编程时,我们需要处理与所进行 IO 操作有关的更多细节。比如,在调用 write 接口时,你必须要指定不同的文件描述符(File Descriptor),才能够区分所要进行的操作是“向屏幕上输出字符”,还是“向文件内写入数据”。相反,在高级 IO 的实现中,我们并不需要关注这些细节,接口的名称可以直接反映其具体用途。

  两者之所以会在接口使用粒度上存在差异,是由于“低级 IO 与操作系统实现紧密相关”。对于 POSIX 标准来说,其所在系统会将绝大多数的 IO 相关资源,比如文档、目录、键盘、网络套接字,以及标准输入输出等,以“文件”的形式进行抽象,并使用相对统一的数据结构来表示。而在实际编码过程中,每一个可用的 IO 资源都会对应于一个唯一的整型文件描述符值。该值将被作为“单一可信源(The Single Source of Truth)”,供相关接口使用。

  而标准 IO 在接口设计与使用方式上,却不会与某类特定的操作系统进行“绑定”。相反,它会提供更加统一和通用的接口,来屏蔽底层不同系统的不同实现细节,做到“一次编写,到处编译”。

  除此之外,即使上述两段采用不同级别 IO 接口实现的 C 代码,在实际的可观测执行效果方面基本一致,但它们在程序运行时,资源的背后使用逻辑上却有着较大的差异。

  带缓冲的标准 IO 模型

  那么,这两种 IO 模型除了在接口使用方式上有不同外,还有哪些重要差异呢?简单来讲,与低级 IO 相比,标准 IO 会为我们提供带缓冲的输入与输出操作。事实上,标准 IO 接口在实现时,会直接使用所在平台提供的低级 IO 接口。而低级 IO 接口在每次调用时,都会通过系统调用来完成相应的 IO 操作。

  关于系统调用的内容,后面还会提到。在这里你只需要知道,系统调用的过程涉及到进程在用户模式与内核模式之间的转换,其成本较高。为了提升 IO 操作的性能,同时保证开发者所指定的 IO 操作不会在程序运行时产生可观测的差异,标准 IO 接口在实现时通过添加缓冲区的方式,尽可能减少了低级 IO 接口的调用次数。郑州看心理医生哪家好http://www.hyde8731.com/

  让我们再把目光移回到之前的两段示例代码上。不知道你在运行对应的两段程序时,是否有观察到它们之间的差异呢?实际上,使用低级 IO 接口实现的程序,会在用户每次输入新内容到标准输入流中时,同时更新文件 “temp.txt” 中的内容。而使用标准 IO 接口实现的程序,仅会在用户输入的内容达到一定数量或程序退出前,再更新文件中的内容。而在此之前,这些内容将会被存放到缓冲区中。

  当然,C 标准中并未规定标准 IO 接口所使用的缓冲区在默认情况下的大小,对于其选择,将由具体标准库实现自行决定。

  除此之外,标准 IO 还为我们提供了可以自由使用不同缓冲策略的能力。对于简单的场景,我们可以使用名为 fflush 的接口,来在任意时刻将临时存放在缓冲区中的数据立刻“冲刷”到对应的流中。而在相对复杂的场景中,我们甚至可以使用 setvbuf 等接口来精确地指定流的缓冲类型、所使用的缓冲区,以及可以使用的缓冲区大小。

  此时,再次编译并运行程序,其执行细节与之前相比会有什么不同?欢迎在评论区告诉我你的发现。

标签:深入浅出,接口,C语言,标准,IO,使用,缓冲区,低级
来源: https://www.cnblogs.com/gyshht/p/15774672.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有