编译预处理知识点梳理:宏定义+文件包含+条件编译

上一篇文章:C语言字符数组与字符串+十六进制转十进制+字母和汉字的存储差别+bool型变量+反斜杠代码换行

编译预处理

  • 预处理不是C语言本身的组成部分,不能直接对它们进行编译,而是由C预处理器在C编译系统对源代码编译之前,根据预处理命令,先对程序文本进行一定的修改。然后C编译系统再将预处理的结果,和源程序一起进行编译,以得到目标代码。所以,程序的编译工作实际上是由编译预处理、编译两部分工作组成。
  • 合理使用预处理命令,有利于提高代码重用性、程序可读性及程序移植性。
  • 所有的预处理命令都以“#”引导
  • 预处理命令一般出现在所有函数的外部,放在源程序的最上面
  • C语言的提供的编译预处理命令主要有一下三种:
    • 宏定义
    • 文件包含
    • 条件编译

宏定义

无参宏

比如:#define PI 3.14

  • 调用:比如:s=PI*r*r;计算时用3.14代替PI
  • 宏展开:比如:s=3.14*r*r;用3.14替换掉PI就是宏展开
  • 结束宏定义的使用:
#include <stdio.h>
#define N 100
#define PI 3.14
main()
{
	...
}
#undef N
//这个语句就是终止宏定义N的使用,后面的子函数再出现N,就不用100替换了
//而PI仍然可以正常使用,因为没有对它进行#undef终止语句
void fun()
{
	...
}
  • 宏嵌套定义:
    比如:
#define PI 3.14
#define s PI*r*r//再次宏定义时,里面使用前面定义好的PI

这就是宏嵌套定义

宏定义的应用
  • 符号常量
    比如:NULL是系统提前定义好的符号常量,代表的是0,即“空”
    #define NULL 0
    再如:EOF,代表的值是-1,文件尾
    #define EOF -1
  • 用宏定义表示数据类型
    比如:#define SINGLE float程序中就可以这样来定义单精度浮点型变量:SINGLE x,y;这里的x和y是float型的变量
  • 用宏表示输入输出
    比如:
    在这里插入图片描述
  • 用宏定义表示格式输出
    例如:
    在这里插入图片描述
    通俗地说用这种方式可以代替一些编程的语句,可以代替任何编程语句,只要没有语法错误就行,如:
    在这里插入图片描述

有参宏

例如:#define SUM(a,b) a+b注意SUM和后面的括号之间不能有空格,否则编译时会报错,a和b是要传进来的参数,后面的a+b是要执行的语句
在这里插入图片描述
注意无论是有参宏还是无参宏,其本质都是做一个替换,即原模原样的替换如:
#include <stdio.h>
#define F(x,y) 2*x+y
main()
{
int a=3,b=2;
printf("%d",F(a,b)*F(b,a));
}
它输出的是2*a+b*2*b+a=2*3+2*2*2+3=17
在这里插入图片描述
如果想计算(2*a+b)*(2*b+a)的值,那么程序得改为:
#include <stdio.h>
#define F(x,y) (2*x+y)
main()
{
int a=3,b=2;
printf("%d",F(a,b)*F(b,a));
}
这样经过原模原样的替换后,括号也会替换下来
在这里插入图片描述

有参宏的应用
  • 求最大值最小值
    #define MAX(a,b) (a>b?a:b)
    #define MIN(a,b) (a>b?b:a)

等等等很多应用,比如判断大小写字母啊,判断闰年啊什么的,可以用有参宏的定义来实现一个特定的功能,这样后面的程序中可以反复用,比函数要简单多了

文件包含

比如:#include <stdio.h>就是文件包含,stdio.h头文件,.h是英文单词head(头)的缩写,头文件中一般情况下是一些函数的声明,不同的编译器头文件中的内容不同,有的编译器头文件中直接是函数的函数体,把头文件包含进来直接就可以调用里面的函数;也有的编译器头文件中只是函数声明,而它们的函数体放在了库文件中。我们知道当我们想要使用printf()函数和scanf()等函数的时候需要把stdio.h头文件包含进来,因为这些函数都是开发人员写好的函数,我们直接拿过来用就行了,这些函数的函数体一般情况下在库文件中,我们编写源代码的时候只需要把它们的声明引进来,就可以调用库文件中的函数了,头文件中也可以直接写入函数的函数体,然后用文件包含直接引用就可以了。我们也可以自己把需要的函数写入头文件,按照我们自己的开发需求,写一些需要的函数,然后用文件包含的形式在源文件中引进来,并调用就可以了。
文件包含两种形式:
例如:
#include <stdio.h>
或者
#include "stdio.h"
二者的区别:1.使用双引号:系统首先到当前目录下查找被包含的文件,如果没有找到,再到系统指定的“包含文件目录”(由用户在配置环境时设置)去查找。2.使用尖括号:直接到系统指定的“文件包含目录”去查找。一般来说,使用双引号比较保险,而使用尖括号可以节省查找时间 3.如果被包含文件不在当前目录中,在双引号中需要给出文件的具体路径,如:“C:\LIANXI\file2.c”
文件包含本质上也是一种原模原样的替换,即将被包含文件里面的内容原模原样复制过来,并覆盖#include语句,这样头文件里面的内容就全部被引进我们编写的源代码中了
比如:如下图,我在桌面创建了一个文本文档,里面写入了一个求阶乘的子函数
在这里插入图片描述
写完保存后,修改一下名字,后缀.txt改为.h(不改后缀也可以的)
在这里插入图片描述
然后编写程序的时候我把它的文件路径引入进来,运行并输入4,结果是24:
在这里插入图片描述

  • 包含文件所指明的路径包含文件全名在内不能超过260个字符
  • 文件包含也可以嵌套,比如在file1.c文件中有写入了file2.c,当把file1.c包含的时候同时也把file2.c也包含进去了

常用的标准头文件

ctype.h 字符处理
math.h 与数学处理函数有关的说明与定义
stdio.h 输入输出函数中使用的有关说明和定义
string.h 字符串函数的有关说明和定义
stddef.h 定义某些常用内容
stdlib.h 杂项说明
time.h 支持系统时间函数

条件编译

#if

一般格式为:

#if 表达式//该表达式的值为真(1)时执行程序段1,为假(0)时,执行程序段2
	程序段1;
#else
	程序段2;
#endif

实现条件编译:

#include <stdio.h>
#define FLAG 0
void main()
{
	char s[80];
	int i;
	gets(s);
#if FLAG//FLAG的值为0,所以执行语句段2,如果FLAG的值为1,则执行语句段1
	for(i=0;s[i]!=0;i++)
		if(s[i]>='a'&&s[i]<='z')
			s[i]-=32;
#else
	for(i=0;s[i]!=0;i++)
		if(s[i]>='A'&&s[i]<='Z')
			s[i]+=32;
#endif
puts(s);
}

#ifdef

一般格式为:

#ifdef 标识符
	程序段1;
#else
	程序段2;
#endif

可以没有#else后面的语句

#ifdef 标识符
	程序段1;
#endif

如果#ifdef后面的标识符已经用#define定义过了,则编译程序段1,否则编译程序段2
用条件编译实现三个数的排序:

#include <stdio.h>
#define FLAG 0
void main()
{
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
#ifdef FLAG
	if(a>b)
	{int t=a;a=b;b=t;}
	if(a>c)
	{int t=a;a=c;c=t;}
	if(b>c)
	{int t=b;b=c;c=t;}
#else
	if(a<b)
	{int t=a;a=b;b=t;}
	if(a<c)
	{int t=a;a=c;c=t;}
	if(b<c)
	{int t=b;b=c;c=t;}
#endif
	printf("%d %d %d",a,b,c);
}

在这里插入图片描述
在这里插入图片描述
Have you found any difference?

#ifndef

一般格式和#ifdef一样,不做多说了
作用:与#ifdef是相反的,如果#ifndef后面的标识符没有被#define定义过,则执行程序段1,否则执行程序段2
由于和前面类似,我不多解释了



好了,编译预处理就这么一点内容

下一篇文章

C语言函数(函数嵌套、递归调用)+局部变量和全局变量+extern关键字的使用+Visual Studio简单的使用教程+数据存储类别+内部函数外部函数

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jackey_Song_Odd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值