Unix write()和printf()之间的区别

Unix write()和printf()之间的区别,unix,io,operating-system,system-calls,Unix,Io,Operating System,System Calls,最近我在学习操作系统。我只想知道: 系统调用(如write())和标准库函数(如printf())之间有什么区别?系统调用由操作系统实现,并在内核模式下运行。库函数是在用户模式下实现的,就像应用程序代码一样。库函数可能调用系统调用(例如,printf最终调用write),但这取决于库函数的用途(数学函数通常不需要使用内核)。操作系统中的系统调用用于与操作系统交互。例如,Write()可以用于系统或程序中 虽然标准库函数是特定于程序的,例如printf()将打印出一些内容,但它仅在GUI/命令行中

最近我在学习操作系统。我只想知道:


系统调用(如write())和标准库函数(如printf())之间有什么区别?

系统调用由操作系统实现,并在内核模式下运行。库函数是在用户模式下实现的,就像应用程序代码一样。库函数可能调用系统调用(例如,
printf
最终调用
write
),但这取决于库函数的用途(数学函数通常不需要使用内核)。

操作系统中的系统调用用于与操作系统交互。例如,Write()可以用于系统或程序中

虽然标准库函数是特定于程序的,例如printf()将打印出一些内容,但它仅在GUI/命令行中,不会影响系统

对不起,我无法发表评论,因为我需要50%的声誉才能发表评论


编辑:Barmar有很好的答案

系统调用是对一个函数的调用,该函数不是应用程序的一部分,而是在内核中。内核是一个软件层,它为您提供一些基本功能来抽象硬件。粗略地说,内核是将硬件转化为软件的东西

您最终总是使用
write()
write()
被设计成只写一个字节序列,仅此而已。但是由于
write()
被认为太基本了(您可能希望以十为基础编写一个整数,或者以科学记数法编写一个浮点数,等等),不同类型的编程环境为您提供了不同的库以方便您

例如,C编程语言为您提供了
printf()
,允许您以多种不同的格式编写数据。因此,您可以将
printf()
理解为一个函数,它将数据转换为格式化的字节序列,并调用
write()
将这些字节写入输出。但是C++给了你<代码> cOUT <代码>;Java
System.out.println
,等等。这些函数中的每一个都以调用
write()
(至少在POSIX系统上)结束

需要知道的一件事(重要的)是,这样的系统调用代价高昂!这不是一个简单的函数调用,因为您需要调用自己代码之外的东西,并且系统必须确保您没有尝试做令人讨厌的事情,等等。因此,在高级打印类函数中,内置一些缓冲是非常常见的;这样就不总是调用write,但您的数据被保存在某种隐藏的结构中,只有在确实需要或必要时(缓冲区已满或您确实希望看到打印结果)才被写入


这正是当你管理你的钱时发生的事情。如果很多人每人给你5美元,你就不会把每个人都存入银行!您可以将它们放在您的钱包中(这是打印件),直到钱包已满或您不想再保存它们为止。然后你去银行存了一大笔钱(这是写的)。你知道,把5美元放进钱包比去银行存款快得多。银行是内核/OS。

我正在写一个小程序。目前,它只是从标准输入中读取每一行并将其打印到标准输出。我可以添加一个在循环中写入的调用,它会在每行末尾添加几个字符。但是当我改用printf时,所有额外的字符都会聚集在一起,并一次全部出现,而不是出现在每一行上


似乎使用printf会导致stderr被缓冲。添加
fflush(stdout)修复了输出中的差异

我想提到另一点,
stdio
缓冲区保存在进程的用户空间内存中,而系统调用
write
将数据直接传输到内核缓冲区。这意味着,如果在
write
printf
调用之后
fork
一个进程,刷新可能会导致输出三次,并受到行缓冲和块缓冲的影响,其中两个属于
printf
调用,因为
stdio
缓冲区是通过
fork
在子级中复制的

printf()
是向用户空间公开的用于从C库调用函数的API或接口之一


printf()
实际使用
write()
系统调用。
write()
系统调用实际上负责将数据发送到输出。

因此
write()
每5美元直接存入银行,而
printf()
则等待缓冲区收集到很多东西。这就是为什么当父进程和子进程试图在外围设备上打印内容时,
printf()
可能会产生奇怪的输出。是吗?没错!你理解得很好。最后一段实际上很好地解释了非缓冲和缓冲之间区别的一般概念。我正在为嵌入式设备编程。我将交叉编译的c代码闪存到没有操作系统的设备上。调用write函数是否会导致设备上出现未定义的行为?@mercury0114不一定,如果代码中有write函数,则会调用它。