前言
预处理看起来简单,但是其中的内容也是十分重要的,尤其是对于自定义头文件的编写方式,这可以帮助我们在大型项目编写时分文件编写,更有条理,清晰。以下是我的个人总结,大家可以看看,如有问题可以私信我,欢迎指正。一起加油!!
一、概念
预处理是在编译前所做的工作,编译器自动调用预处理程序对源码中以’#’开头的预处理部分进行处理,处理完毕后,进入源码的编译阶段。
二、宏定义(一般大写)
1.无参宏定义
定义无参宏的基本格式:#define 宏名 宏替换
eg:
#define A 2+3
#include<stdio.h>
int main()
{
printf("%d", A * 2);
return 0;
}
最终输出结果是8而不是10,因为宏定义不会发生其他操作,此时即为不会加上()的意思,所以原表达式即为2+3*2
另外,不能给用宏定义的常量赋值
eg:
#define A 23
A=33;//这就是错误的了
2.带参宏定义:
定义带参宏的基本格式: #define 宏名(参数列表) 宏替换 带参宏可以像函数一样调用
eg1:
#define MAX(a,b) a>b?a:b
#include<stdio.h>
int main()
{
printf("%d", MAX(1,3) * 2);
return 0;
}
最终输出为6,即相当于调用了函数
eg2:
#define M(a,b) a*3+b
#include<stdio.h>
int main()
{
printf("%d", M(1,3) * 2);
return 0;
}
最终输出为9
3.宏定义常量
利用宏定义可以实现定义“假”常量//见上方1.处即为此操作
同样,我们可以通过const关键字定义常量:
普通常量: < const> <数据类型> <常量名> = <常量值>;
eg:const int a=0;
定义成常量后,a值不可被改变,即无法赋值了
三,文件包含
1.概念:
我们想要用库函数就需要包含头文件(包含头文件即为#include·····,包含系统头文件用<>,只会在系统头文件中找),也可以编写自定义头文件,包含自己编写的头文件(包含自定义头文件用””,在自定义头文件中找不到就会在系统头文件中找)。文件包含允许嵌套,即在一个被包含文件中可以包含其它文件。(eg:自定义头文件中可以包含<stdio.h>)
2.自定义头文件的步骤:
在头文件处右键点击,添加新建项,点击头文件,文件名必须是.h结尾,接着回车进入头文件页面,若出现#pragma once,即为下面3.介绍的用来防止头文件重复包含的宏定义语句,接着在头文件中定义函数(方式一),但一般我们不会定义函数在里面,一般只是在头文件中声明函数,接着在新建的同名.c源文件(C语言源文件后缀为.c)中直接引用我们的自定义头文件,之后进行函数的实现,最后就可以在原来的源文件中包含这个头文件来使用我们定义的函数了
方式一示例:
方式二示例:
以上两种方式均可输出 3
3.头文件的重复包含
(在我使用的vs2022中可能优化掉了这个问题,无论是否重复包含都不会出现重定义问题,不过之前版本的是有这个问题的)
头文件的嵌套包含可能会引起头文件的重复包含,因为当.c源文件包含一个包含了头文件a的头文件b时,再让该.c源文件包含头文件a时,头文件a事实上包含了两次,由于包含头文件时,头文件中定义了函数,故多次包含同一个头文件即为多次定义函数,若头文件里面有变量,就会同理出现多次定义变量,从而出现函数和变量的重定义问题; 所以需要避免头文件重复包含,某些宏定义语句可以防止头文件重复包含,如: #pragma once //防止头文件重复包含,不让文件的内容被包含两次,使用时在头文件最前面添加。
但#pragma once是vs的IDE(集成开发环境)独有的,有使用平台的限制,其他平台可能没有
四,条件编译
条件编译也就是根据不同的条件编译不同代码段。
(逻辑同if-else)
1.#if......#else的使用
#if 表达式 //若表达式为真,则编译代码段1,否则编译代码段2.
//是编译而非执行,编译是执行的必要不充分条件,编译了不一定执行,但执行了一定编译了
代码段1;
#else
代码段2;
#endif
2.#ifdef......#endif的使用
方式一:
#ifdef 宏名 //如果定义了宏"宏名",则编译代码段.
代码段;
#endif
方式二:
#ifdef 宏名 //如果定义了宏"宏名",则编译代码段1,否则编译代码段2;
代码段1;
#else
代码段2;
#endif
3. #ifndef......#endif的使用
和2.使用方式一致,不过这个是没定义宏"宏名",则编译代码段1,否则编译代码段2;