【问题标题】:How does scanf() work inside the OS?scanf() 如何在操作系统中工作?
【发布时间】:2010-11-18 04:43:01
【问题描述】:

我一直想知道 scanf()/printf() 如何在硬件和操作系统级别实际工作。数据流向哪里,操作系统在这些时候到底在做什么?操作系统会发出什么调用?等等……

【问题讨论】:

  • 你在说什么操作系统?
  • 我没有查看任何特定的操作系统。 Linux/Unix 类型就可以了。我只是想对情况有一个基本的了解。
  • 它们通常不是操作系统的一部分,而是 C 库(libc、glibc、...)的一部分。 scanf() 最终使用 POSIX read() 和 printf POSIX write()。一些标准的 Unix 编程书籍应该对这个级别有所帮助,例如 UNIX 环境中的高级编程 (APUE)。

标签: c operating-system scanf internals


【解决方案1】:

scanf() 和 printf() 是 libc(C 标准库)中的函数,它们分别调用 read() 和 write() 操作系统系统调用,分别与文件描述符 stdin 和 stdout(fscanf 和 fprintf允许您指定要从中读取/写入的文件流)。

对 read() 和 write()(以及所有系统调用)的调用会导致用户级应用程序“上下文切换”到内核模式,这意味着它可以执行特权操作,例如直接与硬件对话。根据您启动应用程序的方式,“stdin”和“stdout”文件描述符可能绑定到控制台设备(如 tty0)或某种虚拟控制台设备(如 xterm 公开的设备)。 read() 和 write() 安全地将数据复制到称为 'uio' 的内核缓冲区或从内核缓冲区复制数据。

scanf 和 printf 的格式字符串转换部分不会在内核模式下发生,而只是在普通用户模式下(在“libc”内部),系统调用的一般经验法则是尽可能不频繁地切换到内核模式,既可以避免上下文切换的性能开销,也可以确保安全(您需要非常小心内核模式下发生的任何事情!内核模式下的代码越少,操作系统中的错误/安全漏洞就越少)。

顺便说一句..所有这些都是从 unix 角度编写的,我不知道 MS Windows 是如何工作的。

【讨论】:

  • 如果单独读取每个字节,上下文切换听起来很慢。当然,在当今时代,这并不重要,但我只是想知道我的理解是否正确。
  • 读取和写入系统调用需要一些字节作为参数通过 UIO 传输,因此它不必为每个字节进行单独的系统调用。您还会认为对于像 getchar() 这样的简单输入函数,必须对每个字符进行单独调用,但实际上现在 libc 比这更聪明一些,它保留了一个缓冲区(在 libc 内部)。所以它可以通过填充它的缓冲区来避免上下文切换的性能开销,然后在每次 getchar() 或 scanf() 时处理一点,直到缓冲区为空,然后再进行另一个系统调用。
  • 关于“在当今时代这并不重要”的话题,事实上,您会惊讶于一直进行系统调用会对性能产生多么显着的影响。考虑到系统调用的速度至少是常规函数调用的 10 倍。例如,如果您有一个大小为 1024 字节的缓冲区,那么您只进行了 1/1024 的系统调用。编写带有和不带有缓冲区的“cp”命令的 C 实现是一个很好的例子,我会在几分钟后发布它。
  • 我也不知道 MS Windows 是如何工作的。不,认真的。这是一个奇迹,它完全有效:-)
  • 幸运的是,对于很多简单的 C 代码的性能,像 scanfprintf 这样的 stdio 函数不会每次都调用 readwrite。他们(通常,我正在简化)实际上维护了一个缓冲区,他们尽可能少地填充系统调用,以减少进出内核的开关数量。典型的 Windows libc 实现的工作方式大致相同,但使用 ReadFileWriteFile 系统调用。内核内部细节不同,但基本抽象和整体数据流非常相似。
【解决方案2】:

在我的操作系统上,我使用 scanf 和 printf 是基于函数 getch() ant putch()。

【讨论】:

  • 哇,这太棒了。当连接单个客户端时,我设法将输出从 uart 更改为 TCP/IP。它是用于嵌入式系统的简单的非抢占式协作微内核。
【解决方案3】:

我认为操作系统只提供了两个流,一个用于输入,另一个用于输出,这些流抽象了输出数据的呈现方式或输入数据的来源。

所以 scanf 和 printf 所做的只是从任一流中添加字节(或消耗字节)。

【讨论】:

  • 这是高级抽象。我想知道这些流如何与硬件一起工作以及操作系统如何管理所有数据的详细信息。
【解决方案4】:

scanf , printf 等内部所有这些类型的函数都不能直接用 c/c++ 语言编写。 在内部它们都是用汇编语言编写的,使用 keword "asm",任何用关键字 "asm" 编写的东西都直接引入到目标文件中,而与编译无关(不是即使在编译后也发生了变化),并且在汇编语言中,我们已经获得了可以实现所有这些功能的预定义代码......所以简而言之,SCANF PRINTF 等都在内部用汇编语言编写。您可以使用关键字“ASM”设计自己的输入功能。

【讨论】:

    猜你喜欢
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 2018-03-28
    • 2013-02-12
    • 2016-01-01
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多