咱们一般在完成一个程序时,每每习惯将程序写为多文件的,这样就能实现程序的模块化管理,以及分工开发合做。而一些全局变量,全局函数,结构体等就能使各模块联系在一块儿。模块化
在日常你们写代码的过程当中,一般会使用文件包含来联系各代码文件,固然初学者也可能会直接写成多文件程序,没有文件包含,这样也能编译、运行。函数
在这里,写了一些小段的测试代码,来讲明:包含.c文件,,直接多文件,包含.h文件三种方式的区别与应用。测试
1.包含.c文件spa
可能有人不习惯写.h文件,而直接将代码写在.c文件中,其余文件要调用函数则直接包含.c文件。正以下面一段代码:code
//fun.c int h = 0; int cal(int a, int b) { return (2*a+3*b); } //main.c #include "stdio.h" #include "fun.c" //包含.c文件 int main(void) { h = 1; //直接使用fun.c中的变量 int i = 1,j = 2; int c = 0; c = cal(i, j); //直接调用fun.c中的函数 printf("%d\n", c); return 0; }
编译:gcc main.c -o main 直接编译经过,运行正确。对象
咱们再看一个测试程序:blog
//fun.c int h = 0; int cal(int a, int b) { return (2*a+3*b); } //fun1.c #include "fun.c" // 就这一句 //main.c #include "stdio.h" #include "fun.c" //包含.c文件 #include "fun1.c" //添加包含fun1.c int main(void) { h = 1; //直接使用fun.c中的变量 int i = 1,j = 2; int c = 0; c = cal(i, j); //直接调用fun.c中的函数 printf("%d\n", c); return 0; }
编译:gcc main.c -o main 编译报错:h cal 发生了重定义。开发
总结:io
优势:能够直接编译main.c文件,不用编译fun.c,由于在main.c的编译预处理阶段,会将fun.c 的代码直接拷贝过来。读者可使用gcc -E main.c -o main.i 查看预处理后.i文件的代码。发现main.i中将fun.c的代码拷贝了过来。编译
缺点:fun.c不能被多个文件包含,由于这样就会产生变量和函数的多个拷贝,形成严重的重定义,编译通不过。
这种方式可解决较简单程序的文件包含问题,一般不推荐使用。
2.直接多文件
多文件程序中,全局变量能够被外部引用,函数也默认是全局函数,能够被外部使用。废话少说,先上代码:
//fun.c int global_var = 0; int cal(int a, int b) { return (2*a+3*b); } //main.c #include "stdio.h" extern int global_var; // 声明外部变量 int main(void) { global_var =1; //外部变量赋值 int i = 1,j = 2; int c = 0; c = cal(i, j); //外部函数调用 printf("%d\n", c); return 0; }
Makefile书写为:
CFLAG=-Wall -O -g
main:main.o fun.o
gcc $(CFLAG) main.o fun.o -o main
main.o:main.c
gcc $(CFLAG) -c main.c -o main.o
fun.o:fun.c
gcc $(CFLAG) -c fun.c -o fun.o
clean:
rm main.o fun.o main
编译经过,会出现警告信息,说cal为隐含的外部函数。运行正确。结果还算理想,那么咱们再来看一段:
1 int global_var = 0; 2 struct student 3 { 4 int age; 5 int num; 6 }; //定义结构体 7 struct student wang; //定义结构体变量 8 int cal(int a, int b) 9 { 10 return (2*a+3*b); 11 } 12 13 #include "stdio.h" 14 extern int global_var; 15 extern struct student wang; //声明外部结构体变量 16 int main(void) 17 { 18 wang.age = 10; //报错 19 student li; //想使用外部的定义的结构体来定义一个变量 报错 20 global_var =1; 21 int i = 1,j = 2; 22 int c = 0; 23 c = cal(i, j); 24 printf("%d\n", c); 25 return 0; 26 }
一样的编译,main.c文件的编译会出现错误,首先是想使用外部定义的结构体变量(已做声明),报错。而后,想用外部结构体定义一个变量,报错。
总结:
优势:不会出现重定义问题
缺点:一、若是要用到的外部变量多,或是在多处要使用外部变量,则要在每个调用的文件中使用extern声明,比较麻烦。
二、若是是在fun.c中有结构体定义或是类的定义,在main.c中用使用结构体定义变量,或是使用类定义对象。编译不能经过,不知该如何处理。
三、若是是定义在fun.c中的结构体变量,在main.c中要声明外部变量,并使用,会出错。故推知:结构体不能声明为外部变量,只能是包含的头文件中定义的结构体。
解决上述问题的方式就是第三种,包含.h文件方式。
3.包含.h文件
为每个模块都编写一个.c文件,一个.h文件。
.c源文件中放:函数的定义,全局变量的定义,全局结构体变量的定义。
.h头文件中放:函数的声明,全局变量的声明(extern),全局结构体的定义,全局结构体变量的声明。
调用文件(main.c)文件中:包含.h头文件便可。不用声明任何东西。
测试代码以下:
//fun.c #include "fun.h" int global_var = 0; struct student wang; //结构体变量定义 int cal(int a, int b) { return (2*a+3*b); } //fun.h #ifndef _fun_h_ //条件编译,解决文件重复包含所引发的重定义问题 #define _fun_h_ struct student { int age; int num; }; extern int global_var; extern struct student wang; #endif //fun1.c #include "fun1.h" //没有实际代码 //fun1.h #include "fun.h" //包含fun.h //main.c #include "stdio.h" #include "fun.h" #include "fun1.h" //extern int global_var; //extern struct student wang; int main(void) { wang.age = 10; //调用全局结构体变量 struct student li; //定义变量 global_var =1; //使用全局变量 int i = 1,j = 2; int c = 0; c = cal(i, j); printf("%d\n", c); return 0; }
总结:
优势:解决了文件重复包含形成的重定义问题;函数,全局变量,结构体,结构体变量都能在外部调用;每一处调用变量的文件处不用重复的写声明语句,由于声明语句直接写在了.h头文件中,直接包含头文件便可。