内容正文:
项目七 预处理
1
C语言程序设计基础
知识目标
了解预处理
掌握宏定义的用法
掌握文件包含的用法
掌握条件编译的用法
技能目标
学会使用宏定义的用法
学会使用文件包含的用法
学会使用文件包含的用法
学会使用条件编译的用法
思政目标
通过案例弘扬奥林匹克运动精神,培养学生不畏艰难,勇于挑战自我的拼搏精神。
结合国家实时热点,培养学生爱国情怀
2
任务1
——预处理定义
基础篇
3
以#号开头的命令称为预处理命令。预处理命令的作用不是实现程序的功能,而是给C语言编译系统提供信息,通知C编译器对源程序进行编译之前应该做哪些预处理工作。C语言中预处理功能主要包含:宏定义、文件包含和条件编译等。
预处理——基础篇
4
任务2
——宏定义
基础篇
5
语法格式如下:
#define 标识符 字符串
#define:用于标识一个宏定义;
标识符:表示宏名;
字符串:表示宏体,可以是常量、表达式等。
预处理——基础篇
2.1不带参数的宏定义
6
【例7-1】打印最近一次冬奥会的举行时间(使用宏定义)。
【解题思路】使用define定义一个常量2022,表示最近一次冬奥会的举行时间,然后打印输出。
预处理——基础篇
7
【程序代码】
预处理——基础篇
8
【运行结果】
预处理——基础篇
9
注意:
(1)在使用宏定义时,必要时需要加上括号。
(2)宏定义末尾不用加分号。
预处理——基础篇
10
【例7-2】以下程序的输出结果是什么?
预处理——基础篇
11
【运行结果】
预处理——基础篇
12
【程序分析】
程序运行结果为什么不是9而是7呢?这是因为,a=W*3,将W进行替换后为a=1+2*3,从而计算结果a=7。
如果要使得a=9,需要将宏定义改为:
#define W (1+2)
这样替换后,a=(1+2)*3,计算结果则为9。
预处理——基础篇
13
取消宏定义:
其语法格式如下:
#undef 宏名称
预处理——基础篇
14
【例7-3】以下程序的输出结果是什么?
预处理——基础篇
15
【运行结果】
第7行报错:'OG' undeclared。
【程序分析】
程序第6行使用了#undef取消了宏OG,因此在第6行以后当再次使用宏OG时,则宏OG就不存在了,从而会报错。
预处理——基础篇
16
语法格式如下:
#define 标识符(参数1,参数2,…) 字符串
预处理——基础篇
2.2带参数的宏定义
17
【例7-4】定义一个宏用于计算正方形面积。
【解题思路】定义一个带参数的宏定义,计算正方形面积。
预处理——基础篇
18
【程序代码】
预处理——基础篇
19
【运行结果】
带参数的宏定义与函数很相似,但最本质的区别是:
宏定义仅仅是字符串的替换,不会对表达式进行计算;
函数是一段可以重复使用的代码,会被编译,会给它分配内存,每次调用函数,就是执行这块内存中的代码。
预处理——基础篇
20
【例7-5】请看以下两个程序的输出结果?
【程序一】
【程序二】
预处理——基础篇
21
【程序分析】
程序一使用函数,先计算出++x等于6,然后再计算绝对值,最后结果为6;
程序二使用宏定义,进行替换后为((++x) >= 0 ? (++x) : -(++x)),首先进行(++x)>=0判断,这时x的值为6,然后再次执行(++x)操作,x的值变为7。
由此可见,宏和函数只是在形式上相似,本质上是完全不同的。
预处理——基础篇
22
任务3
——文件包含
23
它的作用是将一个源程序文件包含到另一个源程序文件中。
其语法格式有以下两种:
#include <文件名>
#include “文件名”
使用< >时,C编译系统将在系统指定的路径下搜索尖括号中的文件;
使用“ ”时,系统首先会在用户当前的工作目录中搜索双引号中的文件,如果找不到,再按系统指定的路径进行搜索。
预处理——基础篇
24
【例7-6】自己定义头文件,打印2021年是中国共产党成立多少周年。
【解题思路】自己定义一个头文件,其中使用宏定义,在.c文件中调用自己编写的头文件。
预处理——基础篇
25
【程序代码】
文件7-6.h:
文件7-6.c:
预处理——基础篇
26
【运行结果】
预处理——基础篇
27
多个C语言文件该如何去编写?
预处理——基础篇
28
【例7-7】一寸光阴一寸金,寸金难买寸光阴。请编写程序计算今年还剩下多少天?
【解题思路】首先,让用户输入当前的时间,由于每个月份的天数不一样,且存在闰年和平年,闰年的2月份有29天,平年的2月份有28天,因此需要根据是否是闰年调整2月份的日期。在这里我们使用三个文件来实现该功能,分别是:date.h、date.c和main.c
预处理——基础篇
29
【程序代码】
文件date.h:
预处理——基础篇
30
文件date.c:
31
文件main.c:
32
【运行结果】
预处理——基础篇
33
任务4
——条件编译
进阶篇
34
【例7-8】文件之间重复包含问题。
foo.h:
foo2.h:
main.c:
预处理——进阶篇
35
【运行结果】
程序报错:redefinition of 'a’
【程序分析】
该程序在编译时会报错,是因为虽然在foo2.h文件中没有定义变量a,但是该文件引用了foo.h文件,经过预处理之后,在foo2.h中则会出现int a =100语句,那么在main.c中既引用了foo.h文件又引用了foo2.h文件,经过预处理之后,会有两条int a = 100语句,从而会报错变量a被重复定义。
函数——进阶篇
36
条件编译:
是指预处理器根据条件编译指令,有条件地选择源程序代码中的一部分代码作为输出,送给编译器进行编译。主要是为了有选择性地执行相应操作,防止宏替换内容(如文件等)的重复包含。
函数——进阶篇
37
语法格式如下:
#if 常数表达式
程序段1
#else
程序段2
#endif
当条件为真时,则对程序段1进行编译;否则,对程序段2进行编译。
预处理——进阶篇
4.1#if/#else/#endif指令
38
【例7-9】使用#if、#else、#endif实现C语言跨平台,对Win32和X64平台的支持。
【解题思路】先定义两个宏定义,分别表示Win32和X64,然后再定义一个宏,选择一个环境平台,通过#if、#else、#endif指令打印当前支持的平台。
预处理——进阶篇
39
【程序代码】
预处理——进阶篇
40
【运行结果】
预处理——进阶篇
41
#ifdef指令用于判断某个宏是否被定义。
其语法格式如下:
#ifdef 宏名
程序段1
#else
程序段2
#endif
如果宏名已被定义过,则对程序段1进行编译,否则对程序段2进行编译。
预处理——进阶篇
4.2#ifdef指令
42
【例7-10】使用#ifdef指令判断是否输出调试信息。
【解题思路】通过#ifdef来判断是否定义宏DEBUG,如果定义了该宏,则输出调试信息,否则,不输出调试信息。
预处理——进阶篇
43
【程序代码】
预处理——进阶篇
44
【运行结果】
预处理——进阶篇
45
#ifndef指令用于判断某个宏是否未被定义。
其语法格式如下:
#ifndef 宏名
程序段1
#else
程序段2
#endif
如果宏名未被定义过,则对程序段1进行编译,否则对程序段2进行编译。
预处理——进阶篇
4.3#ifndef指令
46
【例7-11】使用#ifndef指令判断是否输出调试信息。
【解题思路】通过#ifndef来判断是否未定义宏DEBUG,如果没有定义该宏,则不输出调试信息,否则,输出调试信息。
预处理——进阶篇
47
【程序代码】
预处理——进阶篇
48
【运行结果】
预处理——进阶篇
49
【例7-12】使用#ifndef指令对例7-8代码进行改正。
文件foo.h:
预处理——进阶篇
50
【运行结果】
预处理——进阶篇
51
任务5
——学生信息管理系统
提高篇
52
【管理系统6-1】由于编辑选项中,录入学生信息以及编辑学生信息均需要输入学生成绩,因此在项目中创建utils.h头文件,在该文件中定义inputScore()函数,用于输入学生的成绩。
预处理——提高篇
53
【程序代码】
utils.h:
预处理——提高篇
54
studentInfo.h:
55
【运行结果】
预处理——提高篇
56
谢谢观看
57
$$