在 C 中将整数转换为字符串时,我对包含stdio.h
有点恼火——这不会用不必要的文件描述符和其他代码使二进制膨胀吗?或者,只有在代码中使用标准 io 文件描述符 stdout、stdin、stdin、stderr(例如使用printf
、scanf
、fprintf
)时,流才会打开?如果我的代码只使用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 系统上stdout
的FILENO_STDOUT
文件描述符)在很大程度上无关紧要。您只需要知道,例如 当main
函数中开始执行时,stdout
将存在。
是否包含stdio
标头与这些文件描述符是否会打开无关。
这些是从程序的操作系统(或 shell)打开的标准流,而不是由程序本身打开。
幕后有很多事情要处理文件、流和格式化输出。是的,包括<stdio.h>
和使用其中的例程会产生大量开销。但是标准流是整个事物系统的一部分。C 库提供用于使用流的例程,操作系统提供用于访问文件系统的调用,命令行 shell 或其他进程在进程启动时提供已打开的流,等等。
对于正常进程,您可以忽略这一点。对于执行命令(由您直接键入或在 shell 脚本中键入),使命令工作的所有事情都是次要成本。此外,可执行文件可能会动态地(而不是静态地)链接到一个或多个标准库。这意味着该库未内置于可执行文件中。它在程序运行时可用,但它与系统中的其他进程共享,并且程序与它的连接几乎不会产生额外的开销。
如果您正在使用某些特殊进程或其他特殊软件,例如网络守护程序或设备驱动程序,则有一些方法可以避免在标准 C 库或其部分库中进行链接。但是,这些都是特定于平台的,您必须提供更多信息(可能在其他 Stack Overflow 问题中),说明您正在尝试执行的操作以及正在使用的平台(硬件、操作系统、开发人员工具)。
一些用于开发特殊软件的工具包括精简的库,这些库提供简单的例程而没有大量开销。
此外,C 允许在不定义事物的情况下声明事物。<stdio.h>
标头声明它所需的各种缓冲区和其他数据结构,但如果不使用这些结构的流或其他功能,链接器可能不会从库中导入定义它们的模块,因此它们不会成为可执行文件的一部分。具体细节取决于 C 实现。
包含 stdio.h 有点恼火——这不会用不必要的文件描述符和其他代码使二进制文件膨胀吗?
不。链接 C 运行时会增加代码,但如果没有它,您将无法执行太多操作。此运行时包含启动代码,可确保标准流可用。在许多系统上,新启动的进程已经从一开始就获取了相应的打开的文件,可能由父进程继承。
实际上,这些流甚至在加载可执行文件之前就已打开。这是通常发生的情况:
-
某些 shell 会解析一个命令,告诉它执行你的程序。此命令可能包括
stdin
、stdout
和 'stderr 的重定向。 -
shell 调用
fork()
来创建新进程。该新进程仍在运行 shell 代码。 -
新进程中的 shell 代码按照它解析的重定向的规定打开输入/输出流。如果你说
2>/dev/null
,它将作为文件描述符2
打开/dev/null
。 -
分叉的 shell 代码调用
exec()
来控制代码。 -
当你的代码写入
stdout
时,它只是写入已经打开的文件描述符2
。
您会看到,文件描述符0
、1
和2
的解释只是将打开的文件描述符传递给进程的约定。您可以指示 shell5>myCoolStream
打开更多文件描述符,或关闭现有的文件描述符。如果是这样,您的流程所期望的,那很好。如果你的流程需要别的东西,那么,这就是你的问题。
因此,是否包含<stdio.h>
除了为printf()
等提供通常的函数原型和类型定义外,没有任何影响。流本身完全不受此影响。