首先,您对#include 会发生什么感到有些困惑。您永远不会“编译”标准库。标准库已经编译并位于库文件中(Windows 上的 .dll 和 .lib 文件,Linux 上的 .a 和 .so 文件)。 #include 的作用是为您提供链接 到标准库所需的声明。
首先要了解#include 指令是它们非常低级。如果您使用 Java 或 Python 编程,#includes 与导入有很大不同。导入在较高级别告诉编译器“此源文件需要使用此包”,编译器会弄清楚如何解决该依赖关系。 C 指令中的#include 表示“获取此文件的全部内容并在编译时将其粘贴到此处。”特别是,#include <stdio.h> 引入了一个文件,该文件包含标准库中所有 I/O 函数的前向声明。然后,当您编译代码时,编译器知道如何调用这些函数并检查它们的类型正确性。
一旦您的程序被编译,它就会链接到标准库。这意味着您的链接器(由您的编译器自动调用)将导致您的可执行文件使用共享标准库(.dll 或 .so),或者将复制静态标准库(.lib 或.a) 到您的可执行文件中。在这两种情况下,您的可执行文件都不会“包含”您不使用的标准库的任何部分。
至于创建图书馆,这是一个有点复杂的话题,我将把它留给其他人,特别是因为根据你的问题的下一部分,我认为这不是你真正想做的事情。
头文件并不总是库的一部分。似乎您拥有的是多个源文件,并且您希望能够在另一个源文件中使用来自一个源文件的函数。您可以在不创建库的情况下做到这一点。您需要做的就是将您希望从其他地方访问的东西 foo.c 的 声明 放入 foo.h 中。声明是函数原型和“外部”变量声明之类的东西。例如,如果 foo.c 包含
int some_global;
void some_function(int a, char b)
{
/* Do some computation */
}
然后为了使这些可以从其他源文件中访问,foo.h 需要包含
extern int some_global;
void some_function(int, char);
然后,你#include "foo.h" 在任何你想使用 some_global 或 some_function 的地方。由于标头可以包含其他标头,因此通常将标头包装在“包含守卫”中,这样声明就不会重复。例如, foo.h 应该是:
#ifndef FOO_H
#define FOO_H
extern int some_global;
void some_function(int, char);
#endif
这意味着每个编译单元(源文件)只会处理一次标头。
至于如何编译它们,切勿将 .h 文件放在编译器命令行上,因为它们不应包含任何可编译的代码(仅声明)。在大多数情况下,编译为完全没问题
cc main.c 1.c 2.c 3.c ... [etc]
但是,如果您有 50 个源文件,那么使用构建系统可能会更方便。在 Linux 上,这是一个 Makefile。在 Windows 上,这取决于您使用的开发环境。您可以在谷歌上搜索,或者在指定平台后提出另一个 SO 问题(因为这个问题已经很广泛了)。
构建系统的优点之一是它们独立编译每个源文件,然后将它们全部链接在一起,这样当您只更改一个源文件时,只需重新编译该文件(以及程序重新链接)而不是重新编译所有内容,包括未更改的内容。当您的程序变大时,这会产生很大的时间差异。