文件组织的作用
- 当程序比较大型时,我们把所有的代码都写在main所在的文件中,势必会显得臃肿,且不容易阅读理解,这时候我们就需要把功能拆分到多个源文件中去
- 将主干要运行的功能放到主函数文件中,通过调用其他文件中实现好的函数,可以使主函数清晰易读
- 最好各个文件中都存放特性类似的封装实现
- 当程序较大时,需要精心进行文件组织,方便自己管理代码
头文件
也就是在项目中经常会见到的后缀为.h的文件。
- 这类文件中主要用于存放一个或多个.c源文件中公共共享的声明部分
- 通过#include 预处理器指令导入头文件中声明,可以在当前文件中使用声明过的内容
C预处理器
预处理器是编译过程中,单独执行的第一个步骤。
文件包含 #include指令
通常用于包含一些公共共享的声明或外部变量以及宏定义声明,比如#include “头文件”
也常用于访问库函数中的函数声明,比如#include<stdio.h>
使用格式
#include <文件名>
#include "文件名"
- #include所在行会被替换成导入文件的内容
- #include有两种使用格式
- 如果是引号引起来,则从源文件所在位置开始查找引用文件,如果不存在按照一定的规则进行查找
- 如果是尖括号括起来,则直接按照一定的规则进行查找引用文件
宏替换#define指令
使用格式
#define name replaceText
- 会将源文件中出现name的地方直接文本替换为replaceText
- 作用域是从定义点开始到源文件末尾
- 使用时一定要注意是直接文本替换,使用不当会导致逻辑异常,结果异常
#include <stdio.h>
#define name 3 + 1
printf("result is %d\n", name * 10); // 3 + 1 * 10而非(3+1)*10
运行结果
result is 13
- 通常情况下#define指令占一行,如果替换文本很长需要换行的话,需要在换行处添加+ENTER
#include <stdio.h>
#define name "aaaaaaaaahjajajajajajajjjjajajajajajajajajaajajajajajajjajajajaj\
ajajajajajajaajjalfgjglaljgslgjlslhlsglhlhsghldlhjklsjals;jslhlshnlhkjlsjhlsjhl;jsl;hjsl;jhls;jhljshjehl\
fjfjfj"
int main(int argc, char const *argv[])
{
printf("result is %s\n", name);
return 0;
}
运行结果:
result is aaaaaaaaahjajajajajajajjjjajajajajajajajajaajajajajajajjajajajajajajajajajajaajjalfgjglaljgslgjlslhlsglhlhsghldlhjklsjals;jslhlshnlhkjlsjhlsjhl;jsl;hjsl;jhls;jhljshjehlfjfjfj
- 宏定义可以带参数
#include <stdio.h>
#define Max(a, b) (a) > (b) ? (a) : (b)
int main(int argc, char const *argv[])
{
printf("result is %d\n", Max(1,3));
return 0;
}
运行结果:
result is 3
取消宏定义 #undef指令
#undef name 之后对标号name将不再进行文本替换。
条件包含
避免对同一个的文件重复包含。
- 比如我现在有三个文件,文件a.c、文件b.h、文件c.h
- a.c中通过#include包含了b.h、c.h
- b.h中通过#include包含了c.h
- 那么在a.c中就相当于重复导入了c.h,在a中会有两份c.h的内容
需要使用条件包含指令,避免这种情况。
条件包含大体有以下几种
- #if-#elif-#else-#endif
- #ifdef-#endif
- 常用这个来进行避免文件重复包含
#ifndef 标号
#define 标号
文件内容
#endif
- 如果没有定义过标号(ifndef===if not defined),则会包含整个文件内容,#endif结束
- 如果之前引用过文件,那么就定义过标号,#ifndef判断为假,直接跳到#endif,就不会再包含文件了