cc程序设计第7章-编译预处理和位运算课件_第1页
cc程序设计第7章-编译预处理和位运算课件_第2页
cc程序设计第7章-编译预处理和位运算课件_第3页
cc程序设计第7章-编译预处理和位运算课件_第4页
cc程序设计第7章-编译预处理和位运算课件_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C/C+程序设计 C/C+程序设计第7章 编译预处理和位运算第7章 编译预处理和位运算 引言 编译预处理是C语言编译系统的一个组成部分。所谓编译预处理是指在对源程序进行编译之前,先对源程序中的编译预处理命令进行处理,然后再将处理的结果和源程序一起进行编译,以得到目标代码,预处理的实现方法是通过几种特殊的命令,在进行程序的编译之前,先对这些命令进行处理。这些预处理命令的介入,可以改进程序的设计环境,提高编程效率。 编译预处理命令均以符号“#”开头,并且规定一行只能写一条预处理命令,命令结束不能使用分号,通常预处理命令都放在源程序的开头。在前面几章的程序中,我们用到的#define 、#inclu

2、de等命令都是编译预处理的应用。 C语言提供了3种预处理命令:宏定义文件包含条件编译第7章 编译预处理和位运算 C语言有两种宏定义命令,一种是不带参数的宏定义(也称符号常量定义),另一种是带参数的宏定义。7.1 编译预处理- 宏定义1. 不带参数的宏定义一般格式为:#define 标识符 字符串说明:1)通常宏名用大写字母表示,以示与普通变量区别。2)宏名与字符替换序列之间用空格符分隔。3)编译预处理时,在程序中进行宏替换(也称宏展开),凡是 宏名出现的地方均被替换为它所对应的字符替换序列。4)编译预处理时只做简单的替换,不进行语法检查更不会做运 算,若字符串有错误,只有在正式编译时才会进行检

3、查。5)没有特殊的需要,一般在预处理语句的行末不必加分号,若 加了分号,则连同分号一起替换。6)使用宏定义可以减少程序中重复书写字符串的工作量,提高 程序的可移植性。#define PI 3.14159f ; area = PI * r * r ;经过宏替换后: area = 3.14159f ; * r * r ; ,显然正式编译时会报告语法错误。 通常当问题规模事先不能确定时,可使用宏定义来定义一个表示问题规模的符号常量。如:#define N 1007)宏定义命令通常放在文件开头或者函数定义之前,宏名的作用域通常从定义开始到所在源文件结束。但使用#undef命令可提前强制终止某个宏的作用

4、域。#define PI 3.14159fvoid main ( ) #undef PI / 结束宏名PI的作用域fun ( )PI的有效范围 这里,#undef PI 之后的代码范围,符号常量PI的宏定义就不再起作用了。8)进行宏定义时,在字符替换序列中可以引用已定义的其它宏名,宏展开时会进行层层替换。例如: #include #define PI 3.1415926f#define R 4.0f#define L 2*PI*R#define S PI*R*Rvoid main ( ) printf ( L=%f , S=%f n , L , S ) ; 经过宏展开后,printf ( )函

5、数调用语句被宏替换为: printf (L=%f n,S=%f n, 2*3.14159f*4.0f , 3.14159f *4.0 f * 4.0f ) ; 2. 带参数的宏定义带参数的宏定义不仅要进行简单的字符串替换,而且还要进行参数替换。一般形式为: #define ( ) 说明:1)宏定义时,宏名与左括号之间不要出现空格,否则会将空格连同后面的所有替换字符序列都作为替换内容进行替换。例如:#define S ( a , b ) a* b 如果程序中有 y = S ( x , y ) ,则被展开为: y = ( a , b ) a* b( x , y )显然这不是想要的结果。2)宏定义中

6、的参数称为形参。程序中使用带参数的宏时,程序中的参数为实参,实参可以是常量、变量或表达式。宏展开时,将替换序列中的形参用相应位置的实参替换;若宏定义的替换序列中的字符不是形参,则在替换时保留。例如: #define S( a , b )a * barea = S( 2 , 3 ) ; 其中a和b称为形参,2和3称为实参,在宏展开时,把2、3分别代替宏定义中的a、b,a * b中的“*”号保留,因此宏展开后语句为“area = 2 * 3 ;”。3)宏定义字符序列中的参数要用圆括号括起来,而且最好把整个字符串也用圆括号括起来,以保证在任何替换情况下都把宏定义作为一个整体,并且可以有一个合理的计算

7、顺序,否则宏展开后,可能会出现意想不到的错误。例如:#define S( r ) 3.14159 * r * rarea = S( a + b ) ; 经过宏展开后变为“area = 3.14159 * a + b * a + b ;”显然,由于宏定义时,对r没有加圆括号造成与设计的原意不符。那么,为了得到形如:area = 3.14159 * ( a + b ) * ( a + b ) ;就应该在宏定义时给字符序列中的形参加上圆括号,即: #define S ( r ) 3.14159 * ( r ) * ( r ) 【例7-1】从键盘输入两个数,输出较小的数。#include #defin

8、e MIN( a , b ) ( ( a ) ( b ) ? ( a ) : ( b ) ) void main( ) int x , y ;printf ( Please input two integers: ) ;scanf ( %d %d , &x , &y ) ;printf ( MIN = %d n, MIN ( x , y ) ) ; 类型区别函数带参数的宏是否计算实参的值先计算出实参表达式的值,然后传递给形参变量。不计算实参表达式的值,直接用实参原样进行简单的替换。何时进行处理、分配内存单元在程序运行时进行值的处理、调用函数时分配临时的内存单元。预编译时进行宏展开,不分配内存单

9、元,不进行值的处理。类型要求实参和形参要有类型声明,且二者类型要匹配。不存在类型问题,只是一个符号表示。调用情况函数的代码仅存在一个拷贝,对函数较大、调用次数较多时比较合算,但调用函数时会产生时间和空间的开销。在程序源代码中只要遇到宏符号,都将其进行宏替换,调用宏时没有时间空间的开销。但调用次数过多时会使程序代码加长很多。参数传递方式有按值传递和按址传递方式对宏不存方式问题,就是简单替换。3. 带参数的宏与函数的区别7.1.2 文件包含文件包含是指一个源文件可以将另外一个源文件的全部内容包含进来,即将另一个C语言的源程序文件嵌入正在进行预处理的源程序中相应位置,一般形式为:#include 或

10、者#include 文件名 说明:1) “文件名”必须用一对尖括号或一对双引号括起来。2) 使用尖括号和使用双引号对应着不同的路径查找策略。尖括号:系统直接在规定的磁盘目录(通常为软件安装目 录下的Include子目录)查找文件。双引号 :首先在当前文件所在目录中查找文件,若没有找 到,再在操作系统的path命令设置的各目录中查找, 若还没有找到,最后才在Include子目录中查找。3) 一个#include命令只能指定一个被包含文件。7.1.2 文件包含4)若#include命令指定的文件内容发生变化,则应该对包含此文件的所有源文件重新编译处理。5)文件包含命令可以嵌套使用,即一个被包含的文

11、件中可以再使用#include命令包含另一个文件,而在该文件中还可以再包含其它文件,通常允许嵌套10层以上。【例7-2】分析图7-1所示的几个C源文件之间的包含关系。#include file2.cfile1.c中其余代码#include file3.cfile2.c其余代码file3.代码cfile1.cfile2.cfile3.c分析: 通过#include “file3.c”命令,使file3.c的代码被加入到文件file2.c中,而 #include “file2.c”又使file2.c被加入到 file1.c中,因此,通过预处理后,在文件“file1.c”中既有“file2.c”的代

12、码也有“file3.c”的代码。两种形式: 指定表达式真假值 或者: 指定某种符号是否定义7.1.3 条件编译 通常C源文件代码都会参与编译。但是,有时希望依据一定条件只对其中一部分代码进行编译,这就是条件编译。1. 指定某种符号已有定义的条件编译命令格式:#ifdef 标识符 程序段1 #else 程序段2 #endif说明:若标识符已经被定义过(一般用#define命令定义),那么编译程序段1,否则编译程序段2,其中#else部分为可选项。7.1.3 条件编译【例7-3】分析下列条件编译代码。 #ifdef DEBUG printf ( x = %d ,y = %dn , x , y )

13、; #endif分析:若标识符DEBUG被定义过,即程序中有宏定义“#define DEBUG”,则编译程序就会编译语句“printf(x=%d,y=%dn, x, y); ”,从而在程序运行时输出x,y的值。若没有宏定义“#define DEBUG”,则此处的printf语句就不参加编译,当然也不会被执行。 注意条件编译与if语句有区别,即不参加编译的程序段在目标程序中没有与之对应的代码。如果是if语句,则不管表达式是否为真,if语句中的所有语句都产生相应的目标代码。7.1.3 条件编译7.1.3 条件编译2. 指定某种符号没有定义的条件编译命令格式: #ifndef 标识符 程序段1 #e

14、lse 程序段2 #endif说明:其意义与#ifdef的意义恰好相反。若标识符没有定义,程序段1参加编译,否则程序段2参加编译。#else部分为可选项。如:#ifndef DEBUG printf ( x = %d , y = %dn , x , y ) ; #endif 若标识符DEBUG没有定义,则编译printf语句,在程序运行时输出x,y的值;若有标识符DEBUG的宏定义,则此处的printf语句就不参加编译,也不被执行。7.1.3 条件编译3. 指定表达式真假值的条件编译命令格式: #if 表达式 程序段1 #else 程序段 2#endif说明:若表达式为“真”(非0),编译程序

15、段1,否则编译程序段2。其中#else部分可以省略。例如:#include #define FLAG 1void main( ) int a = 1 , b = 0 ; #if FLAG a+ ; printf ( a = %d , a ) ; #else b- ; printf ( b = %d , b ) ; #endif此时FLAG为非0,则编译语句“a+ ; printf (a = %d , a) ;”。注意:#if预处理语句中的表达式是在编译阶段计算值的,因而此处的表达式中不能出现变量,必须是常量或用#define定义的标识符。7.1.3 条件编译4.#undef 标识符格式: #u

16、ndef 标识符功能:将已定义的标识符变为未定义的。例如:#include #define FLAG 1void main( ) int a = 1 , b = 0 ; #undef FLAG #ifdef FLAG a+ ; printf(a=%d ,a ) ; #else b- ; printf(b=%d ,b ) ; #endif虽然前面已经定义标识符FLAG,但程序中“#undef FLAG”命令后,标识符FLAG已经变为未定义,故下面程序段只编译语句“b- ; printf ( b = %d , b ) ;”,程序运行结果是b = -1。 程序中的所有数据在计算机内存中都是以二进制的

17、形式储存的。在很多系统的程序开发中,都要求有对二进制的位(bit)进行一些运算和处理。位运算和位处理通常由低级语言来提供,而作为高级语言的C语言也提供了位运算的功能。7.2 位运算7.2 位运算7.2.1 位运算的概念和位运算符 位运算指对存储单元中的数据按二进制位进行的运算和处理。C语言提供了6种位运算符:1)&(按位与) 2) | (按位或) 3) (按位异或) 4) (按位取反)5)(右移)说明:1)位运算符中除了“”以外,均为二目运算符。2)运算对象只能是整型或字符型,不能为实型。3)运算对象均以二进制补码的形式进行运算。4)位运算符的优先级顺序为: (高于)(高于)&(高于)(高于)

18、| 。5)可以与赋值运算符结合成为复合赋值运算符。7.2 位运算7.2.2 不同位运算的运算规则1. “按位与”运算(&) 将两个操作数的对应二进制位进行逻辑与运算。运算规则:将对象的二进制数补码低位对齐,当对应位都为1该位的运算结果为1,否则为0。例如:6&5。应先把6和5以补码表示,再进行按位与运算。运算过程如下:6的补码:0000 01105的补码:0000 0101&运算: 0000 0100再如:-6&5-6的补码: 111110105的补码: 00000101&运算: 0000 0000(注意,运算结果也是补码,故6&5的结果是4)(注意,运算结果也是补码,故-6&5的结果是0)7

19、.2 位运算说明:1)按位与运算的结果也是补码形式。2)“按位与”运算通常用于对一个数中的某些位清0,即需要清0的位与“0”相与。这样不需清0的位仍保持原值不变。【例7-4】变量n为一正整数,写出判断n是奇数的表达式。分析: 判断一个整数是否为的常规表达式为:n % 2 != 0 或 n % 2,在此给出另一种判断方法为:n & 1 != 0 或 n & 1 思考一下,为什么?7.2 位运算2. “按位或”运算() 将两个操作数的对应二进制位进行或运算。运算规则:如果两个相应位有一个为1,则该位的结果为1; 如果两个相应位都为0,则该位的结果为0。例如:0 x65 | 0 x35。运算过程如下:0 x65的补码:0110 01010 x35的补码:0011 0101 | 运算: 0111 0101说明:“按位或”运算通常用于将一个数中的某些二进制位设置成1,即需要置1的那些位与“1”相或。(注意:结果是补码。故,0 x65 | 0 x35的结果是0 x75)【例7-5】设变量n为一正整数,请将该数最低位字节中的偶数位全部置为1,试写出能实现

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论