c语言 - stdio文件描述符(stdin,stdout,stderr)是否被打开,只需从 #include'ing <stdio.h>?



在 C 中将整数转换为字符串时,我对包含stdio.h有点恼火——这不会用不必要的文件描述符和其他代码使二进制膨胀吗?或者,只有在代码中使用标准 io 文件描述符 stdout、stdin、stdin、stderr(例如使用printfscanffprintf)时,流才会打开?如果我的代码只使用snprintf(3)也许还可以?

我拥有的最接近的现成解决方案是将整数转换为双精度浮点数,用于打印不超过小数点的格式字符串的strfromd(3)

bhuwansahni在如何在 C 中将整数转换为字符串中给出了一个很好的自己动手的解决方案?

我不明白如何使用(链接不起作用)itoa_itoa_fitoa_word,尽管_fitoa_word确实显示为带有nm /lib64/libc6.so.6的功能。

即使您不包括stdio.h,它们也会打开。它们是程序的标准流,在运行时已经打开。

程序在实际执行之前需要进行一些初始化。这包括加载符号表、分配内存、初始化静态数据和链接动态库等。此时将打开标准流。然后,控件转到程序中的main()函数并开始执行。

对于第二个问题,标准IO不会使程序膨胀,因为程序几乎总是与标准C库libc链接,并且通常是动态链接的(因此它不会增加可执行文件的大小)。

是的,如果您不使用它们也没关系。您可以仅使用snprintf()之类的东西很好地完成所有操作,但标准流仍将打开。使用与否并不重要。

谢谢保罗·奥吉尔维

不,这些文件不会通过包含头文件来"打开"。包括头文件发生在编译时,即在运行时打开文件。

所有程序都需要在调用main函数之前完成一些初始化。这通常是由程序完成的,而不是真正从main函数开始,而是从其他代码段(由编译器提供的一部分)开始。此预 main 代码将执行程序正常运行所需的一些常规初始化,其中初始化是标准文件的设置。

这些文件是如何创建的,以及它们是否引用一些较低级别的文件句柄(例如,POSIX 系统上stdoutFILENO_STDOUT文件描述符)在很大程度上无关紧要。您只需要知道,例如 当main函数中开始执行时,stdout将存在。

是否包含stdio标头与这些文件描述符是否会打开无关。

这些是从程序的操作系统(或 shell)打开的标准流,而不是由程序本身打开。

幕后有很多事情要处理文件、流和格式化输出。是的,包括<stdio.h>和使用其中的例程会产生大量开销。但是标准流是整个事物系统的一部分。C 库提供用于使用流的例程,操作系统提供用于访问文件系统的调用,命令行 shell 或其他进程在进程启动时提供已打开的流,等等。

对于正常进程,您可以忽略这一点。对于执行命令(由您直接键入或在 shell 脚本中键入),使命令工作的所有事情都是次要成本。此外,可执行文件可能会动态地(而不是静态地)链接到一个或多个标准库。这意味着该库未内置于可执行文件中。它在程序运行时可用,但它与系统中的其他进程共享,并且程序与它的连接几乎不会产生额外的开销。

如果您正在使用某些特殊进程或其他特殊软件,例如网络守护程序或设备驱动程序,则有一些方法可以避免在标准 C 库或其部分库中进行链接。但是,这些都是特定于平台的,您必须提供更多信息(可能在其他 Stack Overflow 问题中),说明您正在尝试执行的操作以及正在使用的平台(硬件、操作系统、开发人员工具)。

一些用于开发特殊软件的工具包括精简的库,这些库提供简单的例程而没有大量开销。

此外,C 允许在不定义事物的情况下声明事物。<stdio.h>标头声明它所需的各种缓冲区和其他数据结构,但如果不使用这些结构的流或其他功能,链接器可能不会从库中导入定义它们的模块,因此它们不会成为可执行文件的一部分。具体细节取决于 C 实现。

我对

包含 stdio.h 有点恼火——这不会用不必要的文件描述符和其他代码使二进制文件膨胀吗?

不。链接 C 运行时会增加代码,但如果没有它,您将无法执行太多操作。此运行时包含启动代码,可确保标准流可用。在许多系统上,新启动的进程已经从一开始就获取了相应的打开的文件,可能由父进程继承。

实际上,这些流甚至在加载可执行文件之前就已打开。这是通常发生的情况:

  • 某些 shell 会解析一个命令,告诉它执行你的程序。此命令可能包括stdinstdout和 'stderr 的重定向。

  • shell 调用fork()来创建新进程。该新进程仍在运行 shell 代码。

  • 新进程中的 shell 代码按照它解析的重定向的规定打开输入/输出流。如果你说2>/dev/null,它将作为文件描述符2打开/dev/null

  • 分叉的 shell 代码调用exec()来控制代码。

  • 当你的代码写入stdout时,它只是写入已经打开的文件描述符2

您会看到,文件描述符012的解释只是将打开的文件描述符传递给进程的约定。您可以指示 shell5>myCoolStream打开更多文件描述符,或关闭现有的文件描述符。如果是这样,您的流程所期望的,那很好。如果你的流程需要别的东西,那么,这就是你的问题。

因此,是否包含<stdio.h>除了为printf()等提供通常的函数原型和类型定义外,没有任何影响。流本身完全不受此影响。

相关内容

最新更新