0Pricing
C Academy · 课时

多文件项目

头文件与翻译单元

多文件项目 是 CoddyKit 上的免费 C Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

为什么要拆分文件

实际程序不会只存在于一个 .c 文件中。将代码拆分到多个文件中可以:

  • 将相关函数归在一起
  • 让编译器只重新构建发生更改的部分
  • 使代码能够在多个项目之间复用
  • 让团队协作时无需不断处理冲突

理解这些部分如何链接起来至关重要。

翻译单元

每个 .c 文件在预处理器展开其中的 #include 后,都会成为一个翻译单元。

编译器会分别将每个翻译单元转换为一个目标文件(.o)。在这一阶段,它并不知道其他文件的内容。

声明与定义

声明告诉编译器某个函数存在以及它的签名。定义则提供函数的实际主体。

其他文件只需要声明就可以调用函数。定义必须且只能存在于一个位置。

int add(int a, int b);          /* declaration: a promise */

int add(int a, int b) {         /* definition: the body */
    return a + b;
}

头文件

声明应放在头文件(.h)中。任何想要使用该函数的文件都应包含此头文件。

头文件是公共接口;与之对应的 .c 文件则是私有实现。

/* math_utils.h */
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

int add(int a, int b);
int mul(int a, int b);

#endif

实现文件

.c 文件会包含自己的头文件,并定义其中的函数。

包含自己的头文件可以让编译器验证定义是否与声明匹配。

/* math_utils.c */
#include "math_utils.h"

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }

使用模块

其他文件包含该头文件并调用其中的函数,无需查看函数主体。

编译器会信任这些声明;稍后,链接器会将调用连接到真正的定义。

/* main.c */
#include <stdio.h>
#include "math_utils.h"

int main(void) {
    printf("%d\n", add(2, 3));
    return 0;
}

编译与链接

分为两个阶段。首先使用 -c 将每个文件编译为目标文件。然后将这些目标文件链接为一个可执行文件。

链接器会在 math_utils.o 中找到 add 的定义,从而解析对它的每次调用。

gcc -c main.c          # -> main.o
gcc -c math_utils.c    # -> math_utils.o
gcc main.o math_utils.o -o app

双引号与尖括号

包含语法会控制搜索路径:

  • #include "math_utils.h" 会先搜索您的项目目录
  • #include <stdio.h> 只搜索系统包含路径

您自己的头文件使用双引号,标准库头文件使用尖括号。

extern 关键字

要在多个文件之间共享全局变量,请在一个 .c 文件中定义它一次,并在头文件中使用 extern 对其进行声明。

extern 表示“这个变量存在于其他位置”,从而避免重复定义。

/* in config.h */
extern int g_verbose;   /* declaration */

/* in config.c */
int g_verbose = 0;      /* the single definition */

static 关键字

在文件作用域中,static 会使函数或变量仅对其翻译单元私有。

静态辅助函数无法从其他文件链接,从而避免名称冲突并隐藏实现细节。这是在 C 中标记内部内容的方式。

/* visible only inside this .c file */
static int helper(int x) {
    return x * 2;
}

单一定义规则

非静态函数或全局对象在整个程序中只能被精确定义一次。您可以在多个文件中声明它,但只能在一个文件中定义它。

对 add 进行两次定义会产生类似 multiple definition of 'add' 的链接器错误。这就是函数体应当放在源文件而不是头文件中的原因。

快速检查

思考哪些内容应当放入头文件。

回顾

现在您已经可以组织多文件项目了:

  • 每个 .c 文件都是一个独立编译为 .o 文件的翻译单元
  • 头文件存放声明;每个定义分别放在一个 .c 文件中
  • 链接器解析跨目标文件的调用
  • extern 用于共享全局对象;static 使文件局部符号保持私有

下一步:使用 Makefile 自动化构建。

常见问题解答

「多文件项目」课时是免费的吗?

是的 — 「多文件项目」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「多文件项目」这节课中我会学到什么?

头文件与翻译单元 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「多文件项目」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 条件编译
  2. 多文件项目
  3. Makefile
  4. 静态库与共享库
← 返回 C Academy