7. 多文件编译

在使用 C 语言编写大型项目的时候,我们通常以函数为单位编写很多个函数,通常这些函数并不会放入在一个 .c 文件内,而是拆分成多个 .c 文件,最后在链接阶段才组成一个大型程序。这种由多个文件组成一个程序的编译方式我们称之为多文件编译

现在假设我们有一个大型的数学计算的程序,由 多个函数组成的。其中 myaddmymul 函数由张三来编写,其中的 main 函数由李四来编写,且会在 main 函数内调用张三写的 myaddmymul 函数。

原本希望得到的程序结构如下:

#include <stdio.h>

int myadd(int x, int y) {
    return x + y;
}

int mymul(int x, int y) {
    return x * y;
}

int main(int argc, char * argv[]) {
    printf("%d\n", myadd(100, 200));  // 300
    printf("%d\n", mymul(300, 400));  // 120000
    return 0;
}

但实际张三写的 mymath.c 文件内容如下:

// filename: mymath.c
int myadd(int x, int y) {
    return x + y;
}

int mymul(int x, int y) {
    return x * y;
}

实际李四写的 main.c 文件内容如下:

// filename: main.c
#include <stdio.h>

int main(int argc, char * argv[]) {
    printf("%d\n", myadd(100, 200));  // 300
    printf("%d\n", mymul(300, 400));  // 120000
    return 0;
}

上述做法虽然将一个大文件拆成了两个文件,但在编译 main.c 文件时会报告警告或错误,原因是 main.c 文件中并不知道 myaddmymul 这两个标识符是什么?张三为此有编写了一个 用于声明这两个标识符的文件 mymath.h

mymath.h 文件内容如下:

// filename: mymath.h
#ifndef __MYMATH_H
#define __MYMATH_H

int myadd(int x, int y);
int mymul(int x, int y);

#endif

上述文件中写了 myaddmymul 这两个函数的声明。其中 #ifndef __MYMATH_H#define __MYMATH_H#endif 是为了防止函数重复包含,即两次 使用 #include "mymath.h" 进行头文件包含时可以避免重复声明这两个函数。宏的名称通常使用文件名大写的方式,有时候前后也会加几个下划线以避免和系统定义的宏产生冲突。

张三完成了上述 mymath.h 头文件的书写。张三和李四再次改写这两个 .c 文件如下。

张三写的 mymath.c 文件内容加入头文件包含如下:

// filename: mymath.c
#include "mymath.h"

int myadd(int x, int y) {
    return x + y;
}

int mymul(int x, int y) {
    return x * y;
}

李四写的 main.c 文件内容加入头文件包含如下:

// filename: main.c
#include <stdio.h>
#include "mymath.h"

int main(int argc, char * argv[]) {
    printf("%d\n", myadd(100, 200));  // 300
    printf("%d\n", mymul(300, 400));  // 120000
    return 0;
}

这样我们就完成了三个文件:mymath.hmymath.cmain.c的编写。

下面我们来将上述文件编译成一个程序 math_proj。假设我们三个文件都放在同一个文件夹 myproject 下。在 GCC 编译器下。通常我们将 .c 文件汇编成为目标文件(.o 文件),在由目标文件链接成为可执行程序 math_proj

编译、链接和运行步骤和结果如下:

weimingze@mzstudio:~/myproject$ ls
main.c  mymath.c  mymath.h
weimingze@mzstudio:~/myproject$ gcc -c -o mymath.o mymath.c -I.
weimingze@mzstudio:~/myproject$ gcc -c -o main.o main.c -I.
weimingze@mzstudio:~/myproject$ gcc -o math_proj mymath.o main.o
weimingze@mzstudio:~/myproject$ ./math_proj
300
120000

gcc 编译选项说明:

可见使用多个文件也可以将上述三个文件编译成一个可执行程序。

实验

将上述示例的源码复制到对应的文件。使用你自己的编译器完成上述程序的编译和运行。

你也可以点击此处直接下载上述示例的源码