




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 程序设计技术基础第1页,共65页。程序设计技术基础(C语言)2022/8/42第10章程序预编译处理第2页,共65页。2022/8/43 C语言是基于函数模式的编程语言,编译器在进行编译的时候,调用不同的函数完成整体的任务。当它需要调用某个函数的时候,需要知道这个函数的函数原型(通常也叫函数声明)。编译系统在获得的函数的基本信息中,要求有函数的入口地址、相关的参数等。如果函数同时参与了其它的运算工作,例如赋值给一个指定的变量,编译系统还需要掌握该函数的返回数据类型。这些相关的信息可以分别放在不同的头文件(H文件)中,系统在编译的过程中自动调用就可以。第3页,共65页。2022/8/44说明什
2、么是宏定义及其运用宏定义说明文件包含的基本概念与具体运用方法文件包含说明条件编译的基本概念与具体运用方法条件编译通过案例说明如何使用预编译资源综合案例本章内容第4页,共65页。2022/8/451C语言编译原理第节第5页,共65页。2022/8/46 使用编辑器编写完成源代码,就可以调用C语言的编译器将源文件转换成机器码。编译器在处理中,一个单元只包含一个源代码文件(.c程序)。如果没有错误生成对应的目标文件(.obj文件)。最终通过连接器将全部的目标文件进行组合后生成对应的可执行文件(.exe文件)交给操作系统执行。在设计过程中可能会遇到一些代码需要重复执行,或某些参数、公式等频繁使用,为了
3、便于程序设计,可以通过预定义方式设置成一些可以替换的代码。第6页,共65页。2022/8/47第7页,共65页。2022/8/48sin(x)=?第8页,共65页。2022/8/492文件包含命令#include第节第9页,共65页。2022/8/410#include /主函数int main()/定义主函数/主函数体开始int max(int x,int y);/对被调用函数max的声明int a,b,c;/定义变量a,b,cscanf(%d,%d,&a,&b); /输入变量a和b的值c=max(a,b);/调用max函数,将得到的值赋给cprintf(max=%dn,c); /输出c的值
4、return 0;/返回函数值为0/主函数体结束#include #include “stdio.h”第10页,共65页。2022/8/411文件包含命令注意事项(1)包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来。例如以下写法都是允许的:#include stdio.h#include但是这两种形式是有区别的:使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找;使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。用户编程时可根据自己文件所在的目录来选择某一种命令形式。(2)一个include命令只能指定一个被
5、包含文件,若有多个文件要包含,则需用多个include命令。(3)文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。第11页,共65页。2022/8/41210.2.1 调用方式1.基本调用方式# include # include 头文件名使用“”将指定的头文件(.h)文件加载到程序中,它指定的文件是在系统的安装目录中。当要引用的头文件是标准的链接库头文件时应当采用此方法。使用“”与“”将指定的头文件则用于自己定义的通用函数,在编写C代码的时候就需要注意定义方式与引用的方式。第12页,共65页。2022/8/41310.2.1 调用方式2.创建一个自己的头文件 在进行程序设计的过
6、程中,我们可以自己创建一个专门的头文件(.h)来保存相应的函数声明,在其它的源文件(.c)中定义函数并调用函数。在函数章节中曾经介绍,在C语言中只能有一个main()函数,但为了实现代码的重用功能,可以将重复出现的函数单独保存成源文件,在调用的时候,多个文件共同进行编译。而使用头文件则可以直接使用这些定义的函数内容。第13页,共65页。2022/8/414# include/从系统安装的位置查找h文件# include func.h/从当前位置查找相应的h文件int main()int a=1,b=2;printf(a,b中%d是小的数字n,min(a,b);printf(a,b中%d是大的数
7、字n,max(a,b);/func.h/自定义获得两个整数中的最小值int min(int a,int b)return ab?b:a;/自定义获得两个整数中的最大值int max(int a,int b)return ab?a:b;第14页,共65页。2022/8/415第15页,共65页。2022/8/416如果将系统提供的math.h加入main()函数会如何?导入的头文件中如果出现同名的函数会如何?思考题第16页,共65页。2022/8/41710.2.2 C语言中典型的库文件 系统提供了丰富的系统文件,称为库文件,C 的库文件分为两类,一类是扩展名为“.h”的文件,称为头文件, 在前
8、面的包含命令中我们已多次使用过。在“.h”文件中包含了常量定义、类型定义、宏定义、函数原型以及各种编译选择设置等信息。另一类是函数库,包括了各种函数的目标代码,供用户在程序中调用。通常在程序中调用一个库函数时,要在调用之前包含该函数原型所在的“.h”文件。第17页,共65页。2022/8/41810.2.2 C语言中典型的库文件典型的头文件ALLOC.H 说明内存管理函数(分配、释放等)。ASSERT.H 定义 assert 调试宏。BIOS.H 说明调用IBMPC ROM BIOS子程序的各个函数。CONIO.H 说明调用DOS 控制台I/O子程序的各个函数。CTYPE.H 包含有关字符分类
9、及转换的名类信息(如isalpha和toascii等)。DIR.H 包含有关目录和路径的结构、宏定义和函数。DOS.H 定义和说明MSDOS和8086调用的一些常量和函数。ERRON.H 定义错误代码的助记符。FCNTL.H 定义在与open库子程序连接时的符号常量。FLOAT.H 包含有关浮点运算的一些参数和函数。第18页,共65页。2022/8/41910.2.2 C语言中典型的库文件典型的头文件GRAPHICS.H 说明有关图形功能的各个函数,图形错误代码的常量定义,对应不同驱动程序的各种颜色值及函数用到的一些特殊结构。需要注意的是此项功能只能运用在DOS编程中。IO.H 包含低级I/O
10、子程序的结构和说明。LIMIT.H 包含各环境参数、编译时间限制、数的范围等信息。MATH.H 说明数学运算函数,还定了HUGE VAL宏,说明了matherr和matherr子程序用到的特殊结构。MEM.H 说明一些内存操作函数(其中大多数也在STRING.H中说明)。PROCESS.H 说明进程管理的各个函数,spawn和EXEC函数的结构说明。SETJMP.H定义longjmp和setjmp函数用到的jmp buf 类型,并说明这两个函数。第19页,共65页。2022/8/420典型的头文件10.2.2 C语言中典型的库文件SHARE.H 定义文件共享函数的参数。SIGNAL.H 定义S
11、IGZZ(Z ZZ)IGN 和SIGZZ(Z ZZ)DFL常量,说明rajse和signal两个函数。STDARG.H 定义读函数参数表的宏。(如vprintf,vscarf函数)。STDDEF.H 定义一些公共数据类型和宏。STDIO.H 定义Kernighan 和Ritchie 在Unix System V中定义的标准和扩展的类型和宏。还定义标准I/O预定义流:stdin、stdout和stderr,说明I/O流子程序。STDLIB.H 说明一些常用的子程序:转换子程序、搜索与排序子程序等。STRING.H 说明一些串操作和内存操作函数。第20页,共65页。2022/8/4213宏定义#
12、define第节第21页,共65页。2022/8/422在介绍C语言的基础定义时,我们知道常量的功能是为了便于程序的开发,对于程序中重复使用的数据或系统使用的语句可以定义为常量。宏定义在一定意义上有些像常量的效果。在基础的编程中,使用常量便于程序编写,而在高级编程中,使用宏定义方式表示更多的思想。例如在语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。第22页,共65页。2022/8/42310.3.1 无参宏定义1.无参宏的宏名后不带参数其中的“#
13、”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。在前面介绍的符号常量的定义就是一种无参宏定义。对于程序中反复使用的表达式进行宏定义。定义无参宏与定义常量的功能相似,它主要解决在代码中出现的重复代码处理,可以有效解决代码重用。这也是面向对象编程的基础思维方式。形式:#define 标识符 字符串第23页,共65页。2022/8/42410.3.1 无参宏定义# include# includemain()int i;printf(请输入一个角度i=);scanf(%d,&i);printf
14、(角度%d的正弦值为sin(%d)=%fn,i,i,sin(3.1415926*i/180);printf(角度%d的余弦值为cos(%d)=%fn,i,i,cos(3.1415926*i/180);【例10-3】输入一个角度数据,分别计算其中的正弦与余弦。第24页,共65页。2022/8/42510.3.1 无参宏定义# include# includemain()int i;printf(请输入一个角度i=);scanf(%d,&i);printf(角度%d的正弦值为sin(%d)=%fn,i,i,sin(3.1415926*i/180);printf(角度%d的余弦值为cos(%d)=%
15、fn,i,i,cos(3.1415926*i/180);# include# include# define PI 3.1415926main()int i;printf(请你输入一个角度i=);scanf(%d,&i);printf(角度%d的正弦值为sin(%d)=%fn,i,i,sin(PI*i/180);printf(角度%d的余弦值为cos(%d)=%fn,i,i,cos(PI*i/180);第25页,共65页。2022/8/42610.3.1 无参宏定义2.字符串处理方式 宏定义的标准概念是处理一个表达式或字符串,前面所演示的效果是最简单的案例,用于替代程序中可能出现了一个常量情况
16、。# define demo(x*x*x+2*x)它表示定义demo表达式(x*x*x+2*x)。在编写源程序时,程序代码中所有的(x*x*x+2*x)都可由demo代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用(x*x*x+2*x)表达式去置换所有的宏名demo,然后再进行编译。在正式编程的时候,习惯上为了区别与标准的变量定义,通常用大写字母定义宏的名称。编译系统本身并不需要考虑大小写,只是为了阅读方便。就如同变量名称建议“见名识义”,使用sum与使用a都可以用于表示累加,但很明显使用“sum”比“a”在概念的体现中更清楚。第26页,共65页。2022/8/42710.3.1 无
17、参宏定义#define DEMO (x*x*x+2*x)main()int s,x;printf(input a number: );scanf(%d,&x);s=3*DEMO+4*DEMO+5*DEMO;printf(s=%dn,s);【例10-4】字符串处理方式。第27页,共65页。2022/8/42810.3.1 无参宏定义需要注意的是,在宏定义中表达式(x*x*x+2*x)两边的括号不能少。否则会发生错误。#define DEMO x*x*x+2*x main()int s,x;printf(input a number: );scanf(%d,&x);s=3*DEMO+4*DEMO+
18、5*DEMO;printf(s=%dn,s);第28页,共65页。2022/8/429(1)宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。(2)宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。10.3.1 无参宏定义使用宏定义注意事项:第29页,共65页。2022/8/430(3)宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用# undef命令。(4)宏名在源程序中若用引
19、号括起来,则预处理程序不对其作宏代换。(5)宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。(6)习惯上宏名用大写字母表示,也允许用小写字母。(7)可用宏定义表示数据类型,使书写方便。(8)对“输出格式”作宏定义,可以减少书写麻烦。10.3.1 无参宏定义使用宏定义注意事项:第30页,共65页。2022/8/43110.3.1 无参宏定义#define DEMO (x*x*x+2*x);main()int s,x;printf(input a number: );scanf(%d,&x);s=3*DEMO+4*DEMO+5*DEMO;printf(s=
20、%dn,s);第31页,共65页。2022/8/43210.3.2 带参宏定义 语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。 例如:有宏定义#define M(y) y*y+3*y,在main()函数中有k=M(5);则在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为:k=5*5+3*5。带参宏定义的一般形式为:#define 宏名(形参表) 字符串带参宏调用的一般形式为:宏名(实参表);第32页,共65页。2022/8/43310.3.2 带参宏定义#define MAX(a,b) (
21、ab)?a:bmain()int x,y,max;printf(input two numbers: );scanf(%d%d,&x,&y);max=MAX(x,y);printf(max=%dn,max);第33页,共65页。2022/8/43410.3.2 带参宏定义对于带参的宏定义有以下问题需要说明例如: #define MAX(a,b) (ab)?a:b 写为:#define MAX(a,b) (ab)?a:b 将被认为是无参宏定义,宏名MAX代表字符串 (a,b)(ab)?a:b。 宏展开时,宏调用语句: max=MAX(x,y);将变为:max=(a,b)(ab)?a:b(x,y)
22、;这显然是错误的。(1)带参宏定义中,宏名和形参表之间不能有空格“”出现。第34页,共65页。2022/8/43510.3.2 带参宏定义对于带参的宏定义有以下问题需要说明(2)在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。第35页,共65页。2022/8/43610.3.2 带参宏定义对于带参的宏定义有以下问题需要说明(3)在宏定义中的形参是标
23、识符,而宏调用中的实参可以是表达式。#define SQ(y) (y)*(y)main()int a,sq;printf(input a number: );scanf(%d,&a);sq=SQ(a+1);printf(sq=%dn,sq);第36页,共65页。2022/8/437对于带参的宏定义有以下问题需要说明10.3.2 带参宏定义(4)在宏定义中,字符串内的形参通常要用括号括起来以避免出错。#define SQ(y) y*ymain()int a,sq;printf(input a number: );scanf(%d,&a);sq=SQ(a+1);printf(sq=%dn,sq);
24、第37页,共65页。2022/8/438对于带参的宏定义有以下问题需要说明10.3.2 带参宏定义(5)带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。函数定义# includemain() int i=1; while(i=5) printf(%dn,SQ(i+);SQ(int y) return(y)*(y);第38页,共65页。2022/8/439对于带参的宏定义有以下问题需要说明10.3.2 带参宏定义宏定义(5)带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理
25、两者的结果有可能是不同的。#define SQ(y) (y)*(y)main() int i=1; while(inum=102; ps-name=Zhang ping; ps-sex=M; ps-score=62.5;#ifdef NUM printf(Number=%dnScore=%fn,ps-num,ps-score);#else printf(Name=%snSex=%cn,ps-name,ps-sex);#endiffree(ps);第48页,共65页。2022/8/4492. 第二种形式与第一种形式的区别是将“ifdef”改为“ifndef”。它的功能是,如果标识符未被#defi
26、ne命令定义过则对程序段1进行编译,否则对程序段2 进行编译。这与第一种形式的功能正相反。#ifndef 标识符程序段1#else程序段2#endif第49页,共65页。2022/8/4503. 第三种形式 它的功能是,如常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。因此可以使程序在不同条件下,完成不同的功能。#if 常量表达式程序段1#else程序段2#endif第50页,共65页。2022/8/451带参数宏的典型缺点:(1)编译后的代码通常会很多。因为对于第一处调用,系统都会将宏的定义内容插入到代码中,因此会导致程序的源代码行变长。宏使用的越多,这种效果就越明
27、显。特别是当宏调用嵌套时,会让程序更加复杂。(2)宏参数不进行数据检测。当一个函数被调用的时候,编译会检查每一个参数来确定它们是否是正确的类型,如果不是,或者由系统自动将参数转换成正确的类型(由低向高级转换),或者由编译器产生一个出错信息,而预处理器不会检查宏参数的类型,也不会进行类型转换。(3)C语言允许用指针指向函数,但不允许用指针指向宏。(4)宏可能会不止一次计算它的参数,而函数只计算一次。第51页,共65页。2022/8/4525其它预处理命令第节第52页,共65页。2022/8/453 #error的作用是,编译程序时,只要遇到#error 就会生成一个编译错误提示消息,并停止编译。
28、 语法格式:#error error-message 注意: 宏串error-message 不用双引号包围。遇到#error 命令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。关于系统所支持的error-message信息,请查找相关资料。1. #error 预处理第53页,共65页。2022/8/4542. #line 预处理#line的作用是改变当前行数和文件名称,它们是在编译程序中预先定义的标识符,其语法格式为:#line numberfilename其中内的文件名可以省略。例如:#line 30 a.h其中,文件名a.h 可以省略不写。 这条命令可以改变当前的行号
29、和文件名,例如上面的这条预处理命令就可以改变当前的行号为30,文件名是a.h。我们知道编译器对C源码编译过程中会产生一些中间文件,通过这条命令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。第54页,共65页。2022/8/4553. #pragma 预处理 在所有的预处理命令中,#pragma 命令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma 命令对每个编译器给出了一个方法,在保持与C和C +语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。第55页,共
30、65页。2022/8/4564. #pragma messagemessage 参数:message 参数是重要的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其语法格式为:#pragma message(“消息文本”)当编译器遇到这条命令时就在编译输出窗口中将消息文本打印出来。当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条命令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86。第56页,共65页。2022/8/4575. #pragma code_seg另一个使用得比较多的pragma 参数是code_seg。其语法格式为:#pragma code_seg( section-name,section-class ) 它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。第57页,共65页。2022/8/4586. #pr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 万亩荒地承包合同经典版
- 销售员劳动合同正规范本
- 软件定制居间合同
- 幼儿表演性舞蹈编创理论
- 小学人美版15.面具教案设计
- 棕色卡通风中小学生遵守班级公约
- 国内给据邮件全名址信息录入操作规范培训课件
- 人教版小学二年级上册数学 2.4 和复习 课时练
- 人力资源培训委托合同模板
- 2025租房合同范本:公寓租赁合同样本
- 《网络传播学概论》(第四版)-课件
- 福建省普通高中毕业生综合素质评价报告
- 五年级《欧洲民间故事》知识考试题库(含答案)
- 废品入库单模板
- PFMEA的严重度SOD的评分和优先级别
- INVOICE-商业发票样本格式
- 圆周率1000000位 完整版
- DB33-1036-2021《公共建筑节能设计标准》
- 岩芯鉴定手册
- 快速排序算法高校试讲PPT
- 甘肃历史与甘肃文化
评论
0/150
提交评论