目录
12.3.1 大程序
多个.c文件
- 当main()中的代码太长了,可以分成多个函数
- 当一个源代码文件太长,合适的做法是分成多个文件
- 两个独立的源代码文件不能编译形成可执行程序
那么如何才能将分开的多个.c文件中的函数合起来呢?
简单来说,你需要新建一个项目,在Devcpp这个软件里,在项目中新建.c文件,在文件里放上函数。(也可以直接将写好的文件放进去)之后编译就可以通过,软件会将其中的源代码文件编译后链接起来。DevCpp可以不建立项目而加入文件
对于其他的IDE,必须要先新建项目再加入。有分开的编译和构建两个选项。编译是对单个源代码文件进行编译,构建是对整个项目做链接。
main.c
#include<stdio.h>
int max(int a,int b);
int main(void)
{
int a=5;
int b=6;
printf("%d\n",max(a,b));
return 0;
}
max.c
int max(int a,int b)
{
return a>b?a:b;
}
编译单元
- 一个.c文件是一个编译单元
- 编译器每次编译只处理一个编译单元,再由链接器链接起来
12.3.2 头文件
在上一节提到的程序中,我们在main函数里保留了max的函数声明,这点会影响程序编译吗?
答案是不会,删掉之后编译仍然可以通过,这是为什么?
我们再将max函数里的数据类型改为double
double max(double a,double b)
{
return a>b?a:b;
}
编译仍然可以通过,但是我们给的值可都是int类型啊?
实际上,两个C文件是分开来编译的,在编译main函数时,C编译器会猜测这里使用的是int类型,而在max.c里用了double类型编译,当main调用函数,编译器链接两个程序时,传入的是int,而函数需要的和返回的都是double,所以,Boom,出错了。
因此想要双方协调一致,需要有一个中间人来通知双方,告诉main函数你不要猜了
头文件
把函数原型放到一个头文件(.h)里,在需要调用这个函数的源代码文件(.c)里用#include引入头文件,救恩那个让编译器知道函数原型。
- 在使用和定义函数的地方都应该#include对应的头文件
- 一般做法是对于任何.c,都有对应的同名.h,把所有对外公开的函数原型和全局变量的声明(因为全局变量可以在多个.c之间共享)都放进去
- 不对外公开的函数,指那些在函数前面加上static关键词限制其只能在当前编译单元中被使用。对于全局变量也可以这样限制,让它只能在当前编译单元使用。
所以这是之前的项目写法:
main.c
#include<stdio.h>
#include"max.h"
int main(void)
{
int a=5;
int b=6;
printf("%d\n",max(a,b));
return 0;
}
max.h
int max(int a,int b);
max.c
#include"max.h"
int max(int a,int b)
{
return a>b?a:b;
}
#include
- 和宏一样,都属于编译预处理指令,在编译之前就处理完毕
- 它会将所在的文件中全部文本内容原封不动地插入所在的地方
- 因此也不是必须要在.c文件的最开始写明#include
一些误区:
- include不是用来引入一个库,只是做文本替换
- stdio.h中,你只能找到printf的函数原型,其代码在另外的地方(.lib)
- 现在的C编译器默认引入所有标准库
- #include<stdio.h>只是为了让编译器知道printf函数的原型,确保你调用时给出正确类型的参数值
" " Or <> ?
- " "表示编译器会首先在当前目录寻找文件,如果找不到,就会到编译器指定的目录去找
- <>表示编译器只在指定的目录寻找(标准库头文件)
- 类似能指定寻找头文件的还有计算机环境变量和编译器命令行参数
12.3.3 声明
想要在整个项目中都能访问到全局变量,需要在.h文件里写相关声明。
max.h
extern int gALL;
int max(int a,int b);
声明 vs 定义
- 声明是不产生代码的东西
函数原型、变量声明、结构声明、宏声明、枚举声明、类型声明、inline函数
- 定义是产生代码的东西
函数、全局变量
声明与头文件
- 只有声明可以放在头文件里,是规则,但不是法律
- (可以放定义,但是会出问题)会造成一个项目中多个编译单元里有重名实体
- * 有些编译器允许几个编译单元里存在同名函数,或者用weak修饰符强调这种存在
重复声明
- 同一个编译单元里,同名的结构不能被重复声明(正常来说不会写两遍,)
- 如果头文件里有结构的声明,这个头文件大概率会被在一个编译单元里被#include多次
- 所以需要“标准头文件结构”
比如说,整个项目有两个.h文件,max.h、min.h,然后在max.h文件里声明了结构,然后在min.h里include了max.h,由于include做的是文本替换,相当于是写了两次声明结构的语句,所以会报错。
因此,重复引用经常会造成这种事情。如何解决呢?
标准头文件结构
#ifndef _MAX_H_//如果这个.c里没定义过
#define _MAX_H_//那就定义一个
...
...
...//各种有关MAX_H的语句
#endif//结束if
如果已经存在过(别的头文件已经写了一遍这个宏),中间的语句都不会执行
使用条件编译和宏,就可以保证这个头文件在一个编译单元中只会被#include一次
#pargma once(vs)也可以起到相同的作用,但不是所有编译器都支持