多文件组织
概念:当一个完整的程序被存放在多于一个文件中时,称为程序的多文件组织。
意义:在设计一个功能复杂的大程序时,为了便于程序的设计和调试,通常将程序分成若干个文件,把实现一个模块的程序或数据放在一个文件中。
调用外部函数
代码示例:
main.c:
#include <stdio.h> #include <stdlib.h> int max(int x,int y);//对max函数进行声明 int main() { int a,b,c; printf("输入两数:"); scanf("%d %d",&a,&b); c=max(a,b);//调用另一个文件中的函数 printf("max=%d\n",c); return 0; }max.c:
int max(int x,int y) { int z; z=x>y?x:y; return z; }程序结构图:
结果:
解析:
1.这里将main.c中用到的max函数放在max.c文件中。因为两个文件是同一个项目下的。所以程序运行时可以识别并调用max.c中的max函数。并成功运行。
2.程序运行将从main函数开始。在main函数中调用max函数之前,必须在main.c文件中对max函数进行声明!
3.如果max函数中用到了诸如printf之类的需要头文件的函数,必须在max.c文件中进行include进行头文件声明。
调用外部头文件
代码示例:
main.c:
/*这个程序用来测试外部头文件*/ #include "head.h"//调用外部头文件 int main() { int a; scanf("%d",&a); printf("Test Success!\na=%d",a); return 0; }head.h:
#ifndef HEAD_H_INCLUDED #define HEAD_H_INCLUDED /*头文件从此开始*/ #include <stdio.h> #include <stdlib.h> /*头文件从此结束*/ #endif // HEAD_H_INCLUDED
程序结构图:
结果:
解析:
1.将函数声明、全局变量定义、库函数引用打包成为.h形式的头文件,并在需要时调用,使代码更简洁。提高可读性
2.在main.c中调用头文件注意#include "head.h"要用双引号而非小括号!
程序文件分类:
头文件(.h):
包含:函数声明、全局变量定义、库函数引用
源文件(.c):
包含:主体代码
连编程序:
连编:编译源文件,并将其与库函数文件连接(先编译,后连接)
图解:
解析:
源文件先被编译成.o或.obj文件(后缀名根据系统不同改变)
保存在项目文件夹中的obj文件夹中,如图:
接着将以编译的.o或.obj文件和库函数文件.lib连接,生成.exe的可执行文件
保存在项目文件夹的bin文件夹中,如图:
静态函数与外部函数
外部函数
定义:可供其他文件调用的函数
关键代码:extern
用法:extern 返回值类型 函数名 ([参数表列])
代码示例:
main.c:
#include <stdio.h> #include <stdlib.h> extern int max(int x,int y);//对max函数进行声明,用extern表明max函数的本体在其他文件中。 int main() { int a,b,c; printf("输入两数:"); scanf("%d %d",&a,&b); c=max(a,b);//调用另一个文件中的函数 printf("max=%d\n",c); return 0; }max.c:
extern int max(int x,int y)//用extern使max成为外部函数 { int z; z=x>y?x:y; return z; }结果:
解析:
1.在定义函数时,在函数首部的最左端冠以extern使之成为外部函数。
2.在需要调用此函数的文件中,用extern声明所用的函数是外部函数。
注1:extern是默认参数!既函数定义时不加前缀,则默认是外部函数,允许被其他文件调用。而在其他文件中声明调用外部函数时,即使不使用extern前缀,系统也会默认其调用的是外部函数。(extern可省略)
注2:在编译中,遇到调用外部函数,编译器会假定这个函数的定义存在,只不过在不在当前文件中,并正常产生目标文件。不会因为外部函数未定义报错。
注3:在连接时,会检查编译器得到的若干目标文件中的函数,以及包括的库文件内提供的函数,如果命名唯一,且外部函数定义正常。产生可执行的目标文件(.exe);否则,连接失败。
注4:编写大型程序,需要定义大量函数。对于需要外部调用的函数,应该主动加上extern修饰,以便代码阅读。
静态函数(内部函数)
定义:不可供其他文件调用的函数
关键代码:static
用法:static返回值类型 函数名 ([参数表列])
代码示例:
main.c:
#include <stdio.h> #include <stdlib.h> int max(int x,int y);//对max函数进行声明 int main() { int a,b,c; printf("输入两数:"); scanf("%d %d",&a,&b); c=max(a,b);//调用另一个文件中的函数 printf("max=%d\n",c); return 0; }max.c:
static int max(int x,int y)//使用static将max变成静态函数 { int z; z=x>y?x:y; return z; }结果:
解析:如图,连接时报错,无法找到max函数的定义。
注1:编写大型程序时,需要定义大量的函数。如果这些函数出现重名,会在编译中出现错误。而将函数定义为静态,即使其他文件中出现同名静态函数,也不会冲突。
注2:通常把只允许在同一文件中使用的函数和全局变量前面都冠以static使之局部化,从而其他文件都不能引用。
外部全局变量和静态全局变量
外部全局变量
关键代码:extern
扩展同文件全局变量的作用范围
代码示例:
#include <stdio.h> #include <stdlib.h> /*这个程序用来测试extern扩展全局变量的作用范围*/ int max(int,int); int main() { extern int a,b; printf("%d\n",max(a,b)); return 0; } int a=15,b=-7;//定义全局变量a,b int max(int x,int y) { int z; z=x>y?x:y; return z; }结果:
解析:
通过在main函数中对全局变量做提前引用声明,使得全局变量的作用范围提升了。
声明其他文件中定义的外部变量
代码示例:
main.c:
#include <stdio.h> #include <stdlib.h> /*这个程序用来测试外部变量*/ extern int a,b;//用extern修饰表示这里定义的a,b是外部变量a,b int max(int x,int y); int main() { printf("max=%d\n",max(a,b)); return 0; }max.c:
int a=15,b=-7;//定义全局(外部)变量 extern int max(int x,int y) { int z; z=x>y?x:y; return z; }结果:
解析:
1.通过extern声明,成功在一个文件中调用其他文件中定义的变量。
2.max.c中定义a,b时不能用extern修饰!
3.main.c中的extern可以省略,但为了方便代码阅读,不建议略去。
编译系统对extern的处理
图示:
注1:extern的作用其实是扩展变量的作用范围,声明外部变量也可以说是将外部变量的作用范围扩展到了本文件中。
注2:外部变量将增加程序的耦合性!使得代码变得更加复杂!应当谨慎使用!
静态全局变量
关键代码:static
代码示例:
main.c:
#include <stdio.h> #include <stdlib.h> /*这个程序用来测试外部变量*/ int a=100,b=10;//用extern修饰表示这里定义的a,b是外部变量a,b int max(int x,int y); int main() { printf("max=%d\n",max(a,b)); return 0; }max.c:
static int a=15,b=-7;//定义静态全局变量 extern int max(int x,int y) { int z; z=x>y?x:y; return z; }结果:
解析:
如果max.c中的a,b不用static定义为静态全局变量,将和main中的a,b冲突!
注:静态与外部变量更多更详细的属性,可参考变量类型篇http://blog.csdn.net/aketoshknight/article/details/53790332