(一) 概念相关
- 一个文件里可以包含多个函数,一个函数只能属于一个文件。
- 主函数通常单独占一个文件。
- 其他函数分散在不同的源文件里(根据功能安排所属)
- 为每个源文件编写以.h为扩展名的头文件
主函数所在文件不需要头文件(因为它不被别的函数所调用),只要不分配内存的内容都可以写到头文件里,头文件里至少应该包含对应源文件里所有的函数声明和对应源文件里的全局变量(也可以不包含,见代码说明)。include后<>和""的区别见代码注释。 - 所有的的源文件里使用#include预处理指令包含必要的头文件。
与源文件配对的头文件是必要头文件
如果源文件使用了其他头文件里声明的函数,那么该头文件也是必要头文件
(二)编码
a.c
如下:
#include <stdio.h> //<>表示直接去库查找,如果找不到就真的找不到了
#include "a.h" //双引号表示,在当前项目目录下寻找a.h,如果找不到,就去编译器库里去找,这取决于编译器安装路径
int aCount; // 全局变量,记录函数a在程序运行期间执行了多少次
void a(void){
printf("i'm a, i have run %d times\n", ++aCount);
}
a.h
如下:
#ifndef __A_H__ //防止重复编译,如果还没定义过宏__A_H__,就说明还没具有“需要被编译”的“身份”
#define __A_H__ //定义宏__A_H__,起到一个标记的作用,代表该文件已经具有“需要被编译”的“身份”,预处理结束后会被统一编译
extern int aCount; //只是声明,并不分配内存,调用a.h的文件,都可以使用aCount,如果a.c中还有一个全局变量aaa,如果不写到此处,那么其他文件如果没有包含a.h这个文件,并且其他文件也没有单独写extern语句,那么aaa是不可以被使用的
void a(void);//需要被其他文件调用的函数,如果a.c中有好多函数,但只有这个函数需要被其他文件使用,就写这一个就可以
#endif //__A_H__
b.c
如下:
#include <stdio.h>
extern int aCount;//这条语句代表,aCount是其他文件的全局变量。
//b.c这个文件,使用aCount,可以用#inlcude "a.h"
//但是在此处,我们只想使用aCount,不想让该文件具有使用a.c中函数a的权限,所以,我们可以
//单独将extern int aCount写到b.c这个文件中
void b(void) {
printf("%d\n", aCount);
}
b.h
如下
#ifndef __B_H__ //防止重复编译,如果还没定义过宏__A_H__,就说明还没具有“需要被编译”的“身份”
#define __B_H__ //定义宏__A_H__,起到一个标记的作用,代表该文件已经具有“需要被编译”的“身份”,预处理结束后会被统一编译
void b(void);//需要被其他文件调用的函数
#endif //__B_H__
main.c
如下
#include <stdio.h>
#include "a.h" //调用a函数,需要包含a.h
#include "b.h" //调用b函数,需要包含b.h
int main(void){
a();
b();
return 0;
}
(三)编译
- 在gcc命令后列出所有源文件(.c文件)的路径就可以了,如
gcc main.c test.c
- 把多文件的编译步骤记录到Makefile文件里,然后使用make工具根据Makefile文件内容自动编译
Makefile的学习可以参考 GNU Makefile入门