书签 分享 收藏 举报 版权申诉 / 65
上传文档赚钱

类型C语言程序设计第10章-程序编译预处理.ppt

  • 上传人(卖家):三亚风情
  • 文档编号:3376927
  • 上传时间:2022-08-25
  • 格式:PPT
  • 页数:65
  • 大小:1.32MB
  • 【下载声明】
    1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
    2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
    3. 本页资料《C语言程序设计第10章-程序编译预处理.ppt》由用户(三亚风情)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
    4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
    5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
    配套讲稿:

    如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

    特殊限制:

    部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

    关 键  词:
    语言程序设计 10 程序 编译 预处理
    资源描述:

    1、 程序设计技术基础(C语言)2022-8-82第10章程序预编译处理2022-8-83 C语言是基于函数模式的编程语言,编译器在进行编译的时候,调用不同的函数完成整体的任务。当它需要调用某个函数的时候,需要知道这个函数的函数原型(通常也叫函数声明)。编译系统在获得的函数的基本信息中,要求有函数的入口地址、相关的参数等。如果函数同时参与了其它的运算工作,例如赋值给一个指定的变量,编译系统还需要掌握该函数的返回数据类型。这些相关的信息可以分别放在不同的头文件(H文件)中,系统在编译的过程中自动调用就可以。2022-8-84说明什么是宏定义及其运用说明文件包含的基本概念与具体运用方法说明条件编译的基

    2、本概念与具体运用方法通过案例说明如何使用预编译资源本章内容2022-8-85C语言编译原理2022-8-86 使用编辑器编写完成源代码,就可以调用C语言的编译器将源文件转换成机器码。编译器在处理中,一个单元只包含一个源代码文件(.c程序)。如果没有错误生成对应的目标文件(.obj文件)。最终通过连接器将全部的目标文件进行组合后生成对应的可执行文件(.exe文件)交给操作系统执行。在设计过程中可能会遇到一些代码需要重复执行,或某些参数、公式等频繁使用,为了便于程序设计,可以通过预定义方式设置成一些可以替换的代码。2022-8-872022-8-88sin(x)=?2022-8-89文件包含命令#

    3、include2022-8-810#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的值return 0;/返回函数值为0/主函数体结束#include#include“stdio.h”2022-8-811文件包含命令注意事项(1)包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来。例如以下写法都是允许的

    4、:#include stdio.h#include但是这两种形式是有区别的:u使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找;u使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。用户编程时可根据自己文件所在的目录来选择某一种命令形式。(2)一个include命令只能指定一个被包含文件,若有多个文件要包含,则需用多个include命令。(3)文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。2022-8-81210.2.1 调用方式1.基本调用方式#include#include 头文件名u使用“”将指定的

    5、头文件(.h)文件加载到程序中,它指定的文件是在系统的安装目录中。当要引用的头文件是标准的链接库头文件时应当采用此方法。u使用“”与“”将指定的头文件则用于自己定义的通用函数,在编写C代码的时候就需要注意定义方式与引用的方式。2022-8-81310.2.1 调用方式2.创建一个自己的头文件 在进行程序设计的过程中,我们可以自己创建一个专门的头文件(.h)来保存相应的函数声明,在其它的源文件(.c)中定义函数并调用函数。在函数章节中曾经介绍,在C语言中只能有一个main()函数,但为了实现代码的重用功能,可以将重复出现的函数单独保存成源文件,在调用的时候,多个文件共同进行编译。而使用头文件则可

    6、以直接使用这些定义的函数内容。2022-8-814#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是大的数字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;2022-8-8152022-8-816如果将系统提供的math.h加入mai

    7、n()函数会如何?导入的头文件中如果出现同名的函数会如何?思考题2022-8-81710.2.2 C语言中典型的库文件 系统提供了丰富的系统文件,称为库文件,C 的库文件分为两类,一类是扩展名为“.h”的文件,称为头文件,在前面的包含命令中我们已多次使用过。在“.h”文件中包含了常量定义、类型定义、宏定义、函数原型以及各种编译选择设置等信息。另一类是函数库,包括了各种函数的目标代码,供用户在程序中调用。通常在程序中调用一个库函数时,要在调用之前包含该函数原型所在的“.h”文件。2022-8-81810.2.2 C语言中典型的库文件典型的头文件uALLOC.H 说明内存管理函数(分配、释放等)。

    8、uASSERT.H 定义 assert 调试宏。uBIOS.H 说明调用IBMPC ROM BIOS子程序的各个函数。uCONIO.H 说明调用DOS 控制台I/O子程序的各个函数。uCTYPE.H 包含有关字符分类及转换的名类信息(如isalpha和toascii等)。uDIR.H 包含有关目录和路径的结构、宏定义和函数。uDOS.H 定义和说明MSDOS和8086调用的一些常量和函数。uERRON.H 定义错误代码的助记符。uFCNTL.H 定义在与open库子程序连接时的符号常量。uFLOAT.H 包含有关浮点运算的一些参数和函数。2022-8-81910.2.2 C语言中典型的库文件典

    9、型的头文件uGRAPHICS.H 说明有关图形功能的各个函数,图形错误代码的常量定义,对应不同驱动程序的各种颜色值及函数用到的一些特殊结构。需要注意的是此项功能只能运用在DOS编程中。uIO.H 包含低级I/O子程序的结构和说明。uLIMIT.H 包含各环境参数、编译时间限制、数的范围等信息。uMATH.H 说明数学运算函数,还定了HUGE VAL宏,说明了matherr和matherr子程序用到的特殊结构。uMEM.H 说明一些内存操作函数(其中大多数也在STRING.H中说明)。uPROCESS.H 说明进程管理的各个函数,spawn和EXEC函数的结构说明。uSETJMP.H定义long

    10、jmp和setjmp函数用到的jmp buf 类型,并说明这两个函数。2022-8-820典型的头文件10.2.2 C语言中典型的库文件uSHARE.H 定义文件共享函数的参数。uSIGNAL.H 定义SIGZZ(Z ZZ)IGN 和SIGZZ(Z ZZ)DFL常量,说明rajse和signal两个函数。uSTDARG.H 定义读函数参数表的宏。(如vprintf,vscarf函数)。uSTDDEF.H 定义一些公共数据类型和宏。uSTDIO.H 定义Kernighan 和Ritchie 在Unix System V中定义的标准和扩展的类型和宏。还定义标准I/O预定义流:stdin、stdou

    11、t和stderr,说明I/O流子程序。uSTDLIB.H 说明一些常用的子程序:转换子程序、搜索与排序子程序等。uSTRING.H 说明一些串操作和内存操作函数。2022-8-821宏定义#define2022-8-822在介绍C语言的基础定义时,我们知道常量的功能是为了便于程序的开发,对于程序中重复使用的数据或系统使用的语句可以定义为常量。宏定义在一定意义上有些像常量的效果。在基础的编程中,使用常量便于程序编写,而在高级编程中,使用宏定义方式表示更多的思想。例如在语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“

    12、宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。2022-8-82310.3.1 无参宏定义1.无参宏的宏名后不带参数其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。在前面介绍的符号常量的定义就是一种无参宏定义。对于程序中反复使用的表达式进行宏定义。定义无参宏与定义常量的功能相似,它主要解决在代码中出现的重复代码处理,可以有效解决代码重用。这也是面向对象编程的基础思维方式。形式:#define 标识符 字符串2022-8-82410.3.1 无参宏定义#inc

    13、lude#includemain()int i;printf(请输入一个角度i=);scanf(%d,&i);printf(角度%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】输入一个角度数据,分别计算其中的正弦与余弦。2022-8-82510.3.1 无参宏定义#include#includemain()int i;printf(请输入一个角度i=);scanf(%d,&i);printf(角度%d的正弦值为sin(%d)=%fn,i

    14、,i,sin(3.1415926*i/180);printf(角度%d的余弦值为cos(%d)=%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);2022-8-82610.3.1 无参宏定义2.字符串处理方式 宏定义的标准概念是处理一个表达式或字符

    15、串,前面所演示的效果是最简单的案例,用于替代程序中可能出现了一个常量情况。#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”在概念的

    16、体现中更清楚。2022-8-82710.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=%dn,s);【例10-4】字符串处理方式。2022-8-82810.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*

    17、DEMO+4*DEMO+5*DEMO;printf(s=%dn,s);2022-8-829(1)宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。(2)宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。10.3.1 无参宏定义使用宏定义注意事项:2022-8-830(3)宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。(4)宏名在源程序中若用引号括起来,则预处理

    18、程序不对其作宏代换。(5)宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。(6)习惯上宏名用大写字母表示,也允许用小写字母。(7)可用宏定义表示数据类型,使书写方便。(8)对“输出格式”作宏定义,可以减少书写麻烦。10.3.1 无参宏定义使用宏定义注意事项:2022-8-83110.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=%dn,s);2022-8-83210.3

    19、.2 带参宏定义 语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。例如:有宏定义#define M(y)y*y+3*y,在main()函数中有k=M(5);则在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为:k=5*5+3*5。带参宏定义的一般形式为:#define 宏名(形参表)字符串带参宏调用的一般形式为:宏名(实参表);2022-8-83310.3.2 带参宏定义#define MAX(a,b)(ab)?a:bmain()int x,y,max;printf(input two num

    20、bers:);scanf(%d%d,&x,&y);max=MAX(x,y);printf(max=%dn,max);2022-8-83410.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);这显然是错误的。(1)带参宏定义中,宏名和形参表之间不能有空格“”出现。2022-8-83510.3.2 带参宏定义对于带

    21、参的宏定义有以下问题需要说明(2)在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。2022-8-83610.3.2 带参宏定义对于带参的宏定义有以下问题需要说明(3)在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。#define SQ(y)(y)*(y)main()int a,sq;printf(input a number:);scanf

    22、(%d,&a);sq=SQ(a+1);printf(sq=%dn,sq);2022-8-837对于带参的宏定义有以下问题需要说明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);2022-8-838对于带参的宏定义有以下问题需要说明10.3.2 带参宏定义(5)带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理两者的结果

    23、有可能是不同的。函数定义#includemain()int i=1;while(i=5)printf(%dn,SQ(i+);SQ(int y)return(y)*(y);2022-8-839对于带参的宏定义有以下问题需要说明10.3.2 带参宏定义宏定义(5)带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。#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

    24、(Number=%dnScore=%fn,ps-num,ps-score);#else printf(Name=%snSex=%cn,ps-name,ps-sex);#endiffree(ps);2022-8-8492.第二种形式与第一种形式的区别是将“ifdef”改为“ifndef”。它的功能是,如果标识符未被#define命令定义过则对程序段1进行编译,否则对程序段2 进行编译。这与第一种形式的功能正相反。#ifndef 标识符程序段1#else程序段2#endif2022-8-8503.第三种形式 它的功能是,如常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。因

    25、此可以使程序在不同条件下,完成不同的功能。#if 常量表达式程序段1#else程序段2#endif2022-8-851带参数宏的典型缺点:(1)编译后的代码通常会很多。因为对于第一处调用,系统都会将宏的定义内容插入到代码中,因此会导致程序的源代码行变长。宏使用的越多,这种效果就越明显。特别是当宏调用嵌套时,会让程序更加复杂。(2)宏参数不进行数据检测。当一个函数被调用的时候,编译会检查每一个参数来确定它们是否是正确的类型,如果不是,或者由系统自动将参数转换成正确的类型(由低向高级转换),或者由编译器产生一个出错信息,而预处理器不会检查宏参数的类型,也不会进行类型转换。(3)C语言允许用指针指向

    26、函数,但不允许用指针指向宏。(4)宏可能会不止一次计算它的参数,而函数只计算一次。2022-8-852其它预处理命令2022-8-853#error的作用是,编译程序时,只要遇到#error 就会生成一个编译错误提示消息,并停止编译。语法格式:#error error-message 注意:宏串error-message 不用双引号包围。遇到#error 命令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。关于系统所支持的error-message信息,请查找相关资料。1.#error 预处理2022-8-8542.#line 预处理#line的作用是改变当前行数和文件名称,

    27、它们是在编译程序中预先定义的标识符,其语法格式为:#line numberfilename其中内的文件名可以省略。例如:#line 30 a.h其中,文件名a.h 可以省略不写。这条命令可以改变当前的行号和文件名,例如上面的这条预处理命令就可以改变当前的行号为30,文件名是a.h。我们知道编译器对C源码编译过程中会产生一些中间文件,通过这条命令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。2022-8-8553.#pragma 预处理 在所有的预处理命令中,#pragma 命令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma 命

    28、令对每个编译器给出了一个方法,在保持与C和C+语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。2022-8-8564.#pragma messagemessage 参数:message 参数是重要的一个参数,它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其语法格式为:#pragma message(“消息文本”)当编译器遇到这条命令时就在编译输出窗口中将消息文本打印出来。当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条命令在

    29、编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86。2022-8-8575.#pragma code_seg另一个使用得比较多的pragma 参数是code_seg。其语法格式为:#pragma code_seg(section-name,section-class )它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。2022-8-8586.#pragma once#pragma once(比较常用)只要在头文件的最开始加入这条命令就能够保证头文件被编译一次,这条命令实际上在Visual C+6.0 中就已经有了,但是考虑到兼容性并没有太

    30、多的使用它。2022-8-8597.#pragma hdrstop#pragma hdrstop 表示预编译头文件到此为止,后面的头文件不进行预编译。BCB 可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B 要先于单元A 编译。你可以用#pragma startup 指定编译优先级,如果使用了#pragma package(smart_init),BCB就会根据优先级的大小先后编译。2022-8-860综合案例2022-8-861【例10-17】使用宏定义方式,实现任意层

    31、次的杨辉三角形(小于10)输出效果如图。2022-8-862#include#define c 8/通过修改c的数据,可以输出不同层次的杨辉三角形main()int yhcc;/定义二组数组int i,j;for(i=0;ic;i+)/初始化数组关键数据第一列与最后一列yhi0=1;yhii=1;printf(n%-5d,yh00);/输出第一行printf(n%-5d%-5d,yh10,yh11);/输出第二行for(i=2;ic;i+)printf(n%-5d,yhi0);/输出第一列for(j=1;ji;j+)yhij=yhi-1j+yhi-1j-1;/先计算数组中的值printf(%-5d,yhij);/输出对应位置内容printf(%-5d,yhii);/输出最后一列printf(n);2022-8-863当修改c的数据时(例如修改成11)重新编译运行结果如图所示。2022-8-864【例10-18】使用预定义方式实现两个矩阵相加运算效果如图所示。2022-8-865 语言提供了多种预处理功能,如宏定义、文件包含、条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。本章小结注意本章节知识点!

    展开阅读全文
    提示  163文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
    关于本文
    本文标题:C语言程序设计第10章-程序编译预处理.ppt
    链接地址:https://www.163wenku.com/p-3376927.html

    Copyright@ 2017-2037 Www.163WenKu.Com  网站版权所有  |  资源地图   
    IPC备案号:蜀ICP备2021032737号  | 川公网安备 51099002000191号


    侵权投诉QQ:3464097650  资料上传QQ:3464097650
       


    【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。

    163文库