博客
关于我
编译预处理知识点梳理:宏定义+文件包含+条件编译
阅读量:148 次
发布时间:2019-02-26

本文共 3328 字,大约阅读时间需要 11 分钟。

上一篇文章:

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

编译预处理

  • 预处理不是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 
#define N 100#define PI 3.14main(){ ...}#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 
#define FLAG 0void 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;#endifputs(s);}

#ifdef

一般格式为:

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

可以没有#else后面的语句

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

如果#ifdef后面的标识符已经用#define定义过了,则编译程序段1,否则编译程序段2

用条件编译实现三个数的排序:

#include 
#define FLAG 0void 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

在这里插入图片描述

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

#ifndef

一般格式和#ifdef一样,不做多说了

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



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

下一篇文章

转载地址:http://xpnk.baihongyu.com/

你可能感兴趣的文章
mysqldump数据库备份无法进行操作只能查询 --single-transaction
查看>>
mysqldump的一些用法
查看>>
mysqli
查看>>
MySQLIntegrityConstraintViolationException异常处理
查看>>
mysqlreport分析工具详解
查看>>
MySQLSyntaxErrorException: Unknown error 1146和SQLSyntaxErrorException: Unknown error 1146
查看>>
Mysql_Postgresql中_geometry数据操作_st_astext_GeomFromEWKT函数_在java中转换geometry的16进制数据---PostgreSQL工作笔记007
查看>>
mysql_real_connect 参数注意
查看>>
mysql_secure_installation初始化数据库报Access denied
查看>>
MySQL_西安11月销售昨日未上架的产品_20161212
查看>>
Mysql——深入浅出InnoDB底层原理
查看>>
MySQL“被动”性能优化汇总
查看>>
MySQL、HBase 和 Elasticsearch:特点与区别详解
查看>>
MySQL、Redis高频面试题汇总
查看>>
MYSQL、SQL Server、Oracle数据库排序空值null问题及其解决办法
查看>>
mysql一个字段为空时使用另一个字段排序
查看>>
MySQL一个表A中多个字段关联了表B的ID,如何关联查询?
查看>>
MYSQL一直显示正在启动
查看>>
MySQL一站到底!华为首发MySQL进阶宝典,基础+优化+源码+架构+实战五飞
查看>>
MySQL万字总结!超详细!
查看>>