7. 多文件编译
在使用 C 语言编写大型项目的时候,我们通常以函数为单位编写很多个函数,通常这些函数并不会放入在一个 .c 文件内,而是拆分成多个 .c 文件,最后在链接阶段才组成一个大型程序。这种由多个文件组成一个程序的编译方式我们称之为多文件编译。
现在假设我们有一个大型的数学计算的程序,由 多个函数组成的。其中 myadd 和 mymul 函数由张三来编写,其中的 main 函数由李四来编写,且会在 main 函数内调用张三写的 myadd 和 mymul 函数。
原本希望得到的程序结构如下:
#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 文件中并不知道 myadd 和 mymul 这两个标识符是什么?张三为此有编写了一个 用于声明这两个标识符的文件 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
上述文件中写了 myadd 和 mymul 这两个函数的声明。其中 #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.h、mymath.c、main.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 编译选项说明:
-c选项是汇编成为一个目标文件。-o 文件名是将一个结果输出到一个文件中-I选项是将当前文件夹(.) 成为包含路径。能让#include找到此文件夹。gcc -o math_proj mymath.o main.o是将两个目标文件链接成一个可执行程序math_proj。
可见使用多个文件也可以将上述三个文件编译成一个可执行程序。
实验
将上述示例的源码复制到对应的文件。使用你自己的编译器完成上述程序的编译和运行。
你也可以点击此处直接下载上述示例的源码。