博客
关于我
编译预处理知识点梳理:宏定义+文件包含+条件编译
阅读量: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/

你可能感兴趣的文章
mysql 内连接、自然连接、外连接的区别
查看>>
mysql 写入慢优化
查看>>
mysql 分组统计SQL语句
查看>>
Mysql 分页
查看>>
Mysql 分页语句 Limit原理
查看>>
MySql 创建函数 Error Code : 1418
查看>>
MySQL 创建新用户及授予权限的完整流程
查看>>
mysql 创建表,不能包含关键字values 以及 表id自增问题
查看>>
mysql 删除日志文件详解
查看>>
mysql 判断表字段是否存在,然后修改
查看>>
MySQL 到底能不能放到 Docker 里跑?
查看>>
mysql 前缀索引 命令_11 | Mysql怎么给字符串字段加索引?
查看>>
mysql 协议的退出命令包及解析
查看>>
mysql 取表中分组之后最新一条数据 分组最新数据 分组取最新数据 分组数据 获取每个分类的最新数据
查看>>
mysql 四种存储引擎
查看>>
MySQL 基础模块的面试题总结
查看>>
MySQL 备份 Xtrabackup
查看>>
mysql 多个表关联查询查询时间长的问题
查看>>
mySQL 多个表求多个count
查看>>
mysql 多字段删除重复数据,保留最小id数据
查看>>