库头文件只包含函数的声明。那么,当我们调用库函数时,函数究竟是如何运行的呢?
例如:int strcmp ( const char * str1, const char * str2 );
是 C 中 strcmp 函数的声明。
当我们在程序中调用 strcmp 函数时,如果函数体不存在于头文件中,strcmp 函数究竟是如何执行的呢?
库头文件只包含函数的声明。那么,当我们调用库函数时,函数究竟是如何运行的呢?
例如:int strcmp ( const char * str1, const char * str2 );
是 C 中 strcmp 函数的声明。
当我们在程序中调用 strcmp 函数时,如果函数体不存在于头文件中,strcmp 函数究竟是如何执行的呢?
头文件只包含函数声明。这是他们的主要目的之一,公开您必须使用的内容而不用担心实施
至于实现的位置,运行时库会在构建时添加到您的程序中,因此作为编码人员,您可以调用所有这些函数,因为您对它们的函数定义有“前向”声明,但它不是直到加载实现的运行时。
这样做的原因是因为在每个使用它的程序中复制诸如 printf 之类的实现代码是很愚蠢的。这将非常浪费内存!因此,只有声明向您、程序员公开,并且操作系统在运行时共享内存中函数的实现。
要理解程序如何使用 strcmp ,编译器只看到它的声明就必须理解链接的过程。编译 C 程序包括三个步骤:
第三步,所谓的链接器(通常ld
)基本上将所有链接的目标文件的内容转储到一个可执行文件中并解析所有符号。符号是任何具有全局名称的东西,例如函数或全局变量。
当您的程序调用strcmp
编译器生成的目标文件时,实际上并不包含所述函数的定义。相反,只是strcmp
对链接器稍后将解析的符号的引用。链接器检查所有目标文件和全局库,然后解析这些引用。
strcmp
位于运行时库中,当您构建可执行文件时,它会添加到您的程序中。其工作原理的细节因操作系统而异。
在这种情况下,它与任何其他用户定义的标头没有什么不同。
如果您不包含相应的标头(例如string.h
for strcmp
),则编译器会完成隐式声明。
如果在运行时未找到函数定义(即根据您的假设在库中丢失),则链接器将在与默认完成的标准 C 库链接时抱怨(例如,在-lc
gcc 的情况下执行时) )。
您想要使用的代码printf
已经编译并存储在某处。当链接器将您的目标代码与标准库链接时,您的最终可执行文件就生成了。
试着gcc -c somefile.c
看看你得到了什么。
还可以尝试gcc -v
选项并了解它提供的输出。
找出ld
命令的作用,您将得到答案。
这也是我认为应该对您有所帮助的:关于编译/链接/相关的所有内容
更新 :
还想象一下,如果您为其中printf
的每个程序定义stdio.h
并包含stdio.h
程序.c:
#include <stdio.h> //suppose this contains definition of printf
int main()
{
/*Call printf() somewhere or maybe not */
}
gcc program.c -o 输出
所以在这里你所有的定义都stdio.h
将在文件中被替换,program.c
你的可执行文件output
将变得非常巨大。printf
相反,在stdio.h
需要时从一个地方调用您经常使用的函数会是一个更好的主意
它存在于编译的库中。当您在链接到某个库的同时编译项目时,预编译的库会被添加到最终编译中。