我正在学习C语言,并正在浏览Linux目录中的一些头文件/usr/include
例如stdio.h
,stdlib.h
等。真正困扰我的是,我看到所有函数都用一个extern
关键字定义,这意味着它们只是在没有任何定义的情况下声明,例如:
extern FILE *fopen (__const char *__restrict __filename,
__const char *__restrict __modes) __wur;
每个其他头文件中的所有其他函数也是如此。我的问题是,如果它们只是被声明,它们的实现在哪里?它们必须在某个地方实施,对吗?
这些被称为函数原型。它们告诉编译器该函数存在,但不知道在哪里(还)。编译器使用它来确保您正确调用函数,仅此而已。
编译器完成后,将调用链接器。这就是魔术发生的地方。链接器确定哪个库具有函数的实际实现。在这种情况下,它可能会在标准库中(在某些系统上称为libc),该库会自动拉入。链接器执行其操作,然后由库处理对该函数的调用。
如果原型存在,但找不到实现,则会出现链接器错误(类似于"未定义的符号")。如果缺少原型,代码将编译,但您可能会收到有关它的警告(感谢 Jim Balter 提供有关此的信息)。
头文件仅定义标准库函数的接口,而不定义实现;它们(通常)不包含任何可执行代码。
这取决于编译器和平台,但通常标准库函数已经编译并收集到二进制文件中,您的代码链接到这些文件以生成可执行文件。
如果您在使用 gcc 的 Linux 系统上,您可以在 /usr/lib
下找到这些库文件。 libc.a
通常包含大部分 C 标准库函数(stdio、stdlib、string 等)。 数学函数单独存储在 libm.a
中。 在正常情况下,gcc 会自动链接到/usr/lib/libc.a
,因此您不必担心。 如果需要使用数学库函数,则需要将-lm
添加到命令行以链接到数学库。
请注意,大多数实现不会提供库函数本身的源代码;您得到的只是预编译的二进制文件。
.h
文件包含声明,定义保存在某个目标文件中的某个位置。更多信息可以在这里找到。