编译预处理与位运算.ppt

上传人:小飞机 文档编号:6016591 上传时间:2023-09-15 格式:PPT 页数:64 大小:1.16MB
返回 下载 相关 举报
编译预处理与位运算.ppt_第1页
第1页 / 共64页
编译预处理与位运算.ppt_第2页
第2页 / 共64页
编译预处理与位运算.ppt_第3页
第3页 / 共64页
编译预处理与位运算.ppt_第4页
第4页 / 共64页
编译预处理与位运算.ppt_第5页
第5页 / 共64页
点击查看更多>>
资源描述

《编译预处理与位运算.ppt》由会员分享,可在线阅读,更多相关《编译预处理与位运算.ppt(64页珍藏版)》请在三一办公上搜索。

1、嵌入式C语言高级编程篇,课程目标,了解嵌入式C语言编程特点和操作细节结合嵌入式环境深入理解指针、数组和函数提高编程实践和编程程序规范理解熟悉C语言标准库应用和特点,课程结构图,编译预处理与位运算,第1章,本章目标,本章概述 讲述宏定义的标准用法和位操作的基本应用了解预编译的概念,掌握宏定义的方法。了解“文件包含”与预处理的应用。了解条件编译的几种形式。掌握各种位运算符,运算规则和优先级。了解位运算的实际应用。了解位段的定义和应用。本章目标 了解一些C语言特殊的宏定义熟悉位运算的基本操作重点 宏定义操作,本章结构,编译预处理,编译预处理和位运算,位段,文件包含,宏定义,条件编译,位运算,预处理其

2、他关键词,1 编译预处理与位运算,编译预处理宏定义文件包含条件编译位运算位段其他预处理关键字,1.1编译预处理,作用:对源程序编译之前做一些处理,生成扩展C源程序种类宏定义#define#ifdef#ifndef文件包含#include条件编译#if-#else-#endif等其他宏定义#line#error#pragma格式:“#”开头占单独书写行语句尾不加分号,1.2 宏定义,undef无参数宏定义有参数宏定义,1.2.1 undef,undef定义指令删除前面定义的宏名字。表达一般形式为:#undef macro-name例子define MICRO 1undef MICRO,1.2.2

3、 无参数宏定义,如 if(x=YES)printf(“correct!n”);else if(x=NO)printf(“error!n”);展开后:if(x=1)printf(“correct!n”);else if(x=0)printf(“error!n”);,不带参数宏定义一般形式:#define 宏名 宏体功能:用指定标识符(宏名)代替字符序列(宏体),如#define YES 1#define NO 0#define PI 3.1415926#define OUT printf(“Hello,World”);,宏体可缺省,表示宏名定义过或取消宏体,例#define MAX MAX+10

4、(),例#define PI 3.14159 printf(“2*PI=%fn”,PI*2);宏展开:printf(“2*PI=%fn”,3.14159*2);,例#define WIDTH 80#define LENGTH WIDTH+40 var=LENGTH*2;宏展开:var=80+40*2;,1.2.2 不带参数宏定义,宏定义的规则宏名一般习惯用大写字母表示,以便与变量名相区别宏定义不是C语句,不必在行末加分号在进行宏定义时,可以引用已定义的宏名,可以层层替换。只作字符替换,不分配内存空间。,#define R 3.0#define PI 3.1415926#define L 2*P

5、I*R#define S PI*R*Rmain()printf(“L=%fnS=%fn”,L,S);,结果:L=18.849556 S=28.274333,1.2.2 不带参数宏定义,宏定义的特点宏名一般习惯用大写字母表示提高程序的通用性宏名的有效范围为定义命令之后到本源文件结束可以用#undef命令终止宏定义的作用域宏定义只作简单的替换,不作正确性检查,1.2.3 带参数宏定义,一般形式:#define 宏名(参数表)宏体,例#define S(r)PI*r*r相当于定义了不带参宏S,代表字符串“(r)PI*r*r”,宏展开:形参用实参换,其它字符保留宏体及各形参之间应加空格注意宏体的括号,

6、例#define S(a,b)a*b.area=S(3,2);宏展开:area=3*2;,不能加空格,例#define POWER(x)x*x x=4;y=6;z=POWER(x+y);宏展开:z=x+y*x+y;一般写成:#define POWER(x)(x)*(x)宏展开:z=(x+y)*(x+y);,1.2.2 带参数宏定义,带参数宏定义的特点带参宏定义中,宏名和形参表之间不能有空格出现 例如:#define MAX(a,b)(ab)?a:b写为:#define MAX(a,b)(ab)?a:b 将被认为是无参宏定义,宏名MAX代表字符串(a,b)(ab)?a:b 在带参宏定义中,形式参

7、数不分配内存单元,因此不必作类型定义 在宏定义中的形参是标识符,而宏调用中的实参可以是表达式 在宏定义中,字符串内的形参通常要用括号括起来以避免出错,#define SQ(y)(y)*(y)main()int a,sq;printf(input a number:);scanf(%d,1.2.2 带参数宏定义,带参的宏和带参函数很相似,但有本质上的不同,1.2.2 带参数宏定义,带参的宏和带参函数很相似,但有本质上的不同,宏定义例,函数例,main()int i=1;while(i=5)printf(%dn,SQ(i+);SQ(int y)return(y)*(y);,#define SQ(y

8、)(y)*(y)main()int i=1;while(i=5)printf(%dn,SQ(i+);,1.3 文件包含,函数例,功能:一个源文件可将另一个源文件的内容全部包含进来一般形式:#include“文件名”或#include,处理过程:预编译时,用被包含文件的内容取代该预处理命令,再对“包含”后的文件作一个源文件编译,直接按标准目录搜索“”先在当前目录搜索,再搜索标准目录,1.3 文件包含,被包含文件内容源文件(*.c)头文件(*.h),宏定义数据结构定义函数说明等,文件包含可嵌套,1.3 文件包含,例子,1.3 文件包含,文件包含特点一个include命令只能指定一个被包含文件可以用

9、双引号括起来,也可以用尖括号括起来。文件包含允许嵌套被包含文件(file2.h)与其所在的文件(file.c)在预编译之后已成为同一个文件,1.4 条件编译,#if、#else、#elif#endif#ifdef和#ifndef,1.4.1#if、#else、#elif#endif,条件编译指令中最常用的或许是#if,#else,#elif和#endif#if的一般形式是:#if constant-expressionStatement sequence#endif#endif标记#if块的结束 例子:#ifdef COMPUTER_A#define INTEGER_SIZE 16#else#

10、define INTEGER_SIZE 32#endif,1.4.1#if、#else、#elif#endif,条件编译指令中最常用的或许是#if,#else,#elif和#endif#if的一般形式是:#if constant-expressionStatement sequence#endif#endif标记#if块的结束 例子:#ifdef COMPUTER_A#define INTEGER_SIZE 16#else#define INTEGER_SIZE 32#endif,1.4.1#if、#else、#elif#endif,#else指令的作用与C语言的else相似,#if指令失败时

11、它可以作为备选指令#else既是标记#if块的结束,也标记#else块的开始 每个#if只能写一个#endif匹配 例子:,#include#define MAX 100Int main(void)#if MAX99printf(“Compiled for array greater than 99.n”);#elseprintf(“Complied for small array.n”);#endif return 0;,1.4.1#if、#else、#elif#endif,#elif指令的意思是“否则,如果”语法格式:#if expressionStatement sequence#eli

12、f expression1Statement sequence#elif expression2。#elif expressionStatement sequence#endif,1.4.2#ifdef和#ifndef,#ifdef 如果已定义#ifdef的一般形式如下:#ifdef 标识符 程序段1#else 程序段2#endif当所指定的标识符已经被#define命令定义过,则在程序编译阶段只编译程序段1,否则编译程序段2。,1.4.2#ifdef和#ifndef,#ifndef 如果已定义#ifdef的一般形式如下:#ifndef 标识符 程序段1#else 程序段2#endif作用是当

13、所指定的标识符未被#define命令定义过,则在程序编译阶段只编译程序段1,否则编译程序段2。它只是第一行与第一种形式不同。这种形式与第一种形式的作用相反#ifndef,1.4.2#ifdef和#ifndef,#ifdef和#ifndef,#inlucde#define T 10int main(void)#ifdef t Printf(“Hi Tn”);#else Printf(“Hi anyonen”);#endif#ifndef M Printf(“M Not Definedn”);#endif return 0;,1.4.2#ifdef和#ifndef,#if 如果已定义#if 的一般

14、形式如下:#if 常量表达式程序段1#else程序段2#endif如常量表达式的值为真(非0),则对程序段1 进行编译,否则对程序段2进行编译,1.4.2#ifdef和#ifndef,#if 例子,#define R 1main()float c,r,s;printf(input a number:);scanf(%f,#endif,阶段小节,宏定义的特点和宏定义的取消带参数宏定义要注意的几个细节条件编译主要应用在那几个方面,它有几种使用方法Include 包含文件的两种方法和他们之间的区别特点,1.5 位运算,按位与运算 按位或运算 按位异或运算 求反运算左移运算 右移运算,1.5 位运算,

15、位运算符的含义位运算是指进行二进制位的运算。功能:c语言提供对内存单元的二进制位的操作,使得c语言能够编写系统软件.位运算符&:按位与|:按位或:按位异或:取反:右移,1.5 位运算,要点:位运算除以外,均为二目运算;运算对象只能为整型或字符型数据.各个位运算符号的使用:,按位与运算,按位与&格式:x&y主要用途:取(或保留)1个数的某(些)位,其余各位置0 规则:对应位均为1时才为1,否则为0:3&9=1。例如,3&9=1:0011&1001 0001=1,1.5.2 按位或运算,按位或|格式:x|y主要用途:参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1

16、规则:对应位均为0时才为0,否则为1:3|9=11。例如,3|9=11:0011|1001 1011=11,1.5.3 按位异或运算,按位异或 格式:xy规则:对应位相同时为0,不同时为1:39=10。主要用途:使1个数的某(些)位翻转(即原来为1的位变为0,为0的变为1),其余各位不变例子:00001001 00000101 00001100(十进制为12),求反运算,求反 格式:y规则:各位翻转,即原来为1的位变成0,原来为0的位变成1:在IBM-PC机中,00 xffff,9=0 xfff6。主要用途:间接地构造一个数,以增强程序的可移植性,1.5.5 左移运算,按位左移 格式:x 位数

17、规则:使操作数的各位左移,低位补0,高位溢出:52=20。,1.5.6 右移运算,按位左移 格式:x位数规则:使操作数的各位右移,移出的低位舍弃;高位:对无符号数和有符号中的正数,补0;有符号数中的负数,取决于所使用的系统:补0的称为“逻辑右移”,补1的称为“算术右移”。例如,20 2=5说明x、y和“位数”等操作数,都只能是整型或字符型数据。除按位取反为单目运算符外,其余均为双目运算符。参与运算时,操作数x和y,都必须首先转换成二进制形式,然后再执行相应的按位运算。例如,5 2=5:10100 00101。,1.5.6 位运算例子,例2 题目:从键盘上输入1个正整数给int变量num,输出由

18、811位构成的数(从低位、0号开始编号)基本思路:(1)使变量num右移8位,将811位移到低4位上。(2)构造1个低4位为1、其余各位为0的整数。(3)与num进行按位与运算。/*程序功能:输出一个整数中由811位构成的数*/,main()int num,mask;printf(Input a integer number:);scanf(%d,程序运行情况:Input a integer number:1000 result=0 x3程序说明:(0 4)按位取0的反,为全1;左移4位后,其低4位为0,其余各位为1;再按位取反,则其低4位为1,其余各位为0。这个整数正是我们所需要的。,1.5

19、.6 位运算例子,例1 题目:从键盘上输入1个正整数给int变量num,按二进制位输出该数。,#include stdio.hmain()unsigned int num,mask,i;printf(Input a integer number:);scanf(%d,程序运行情况:Input a integer number:1000 1000=0000,0011,1110,1000B,1.6 位段,位域的定义和位域变量的说明 位域的使用,位域的定义和位域变量的说明,位段的含义 位段是以位为单位定义长度的结构体类型中的成员.位段的构成例如:struct pack unsigned a:2;un

20、signed b:6;unsigned c:8;int x;data;这个结构体类型的变量在内存中的情况为:,位域的定义和位域变量的说明,也可以使各个字段不恰好占满一个字节struct pack unsigned a:2;unsigned b:6;unsigned c:4;int x;data;则内存中的分配形式为:说明:此处:a,b,c共占2个字节中的12位,空闲4位,int型的x从一个新的字节开始.,位域的定义和位域变量的说明,位域的使用要点一个位域必须存储在同一个字节中,不能跨两个字节 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。由

21、于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。,struct bs unsigned a:4 unsigned:0/*空域*/unsigned b:4/*从下一单元开始存放*/unsigned c:4,位域的定义和位域变量的说明,位域的使用要点位域可以无位域名,这时它只用来作填充或调整位置。,struct k int a:1 int:2/*该2位不能使用*/int b:3 int c:2;,1.6.2 位域的使用,若某个位段要从新的存储单元开始,可以这样定义:注意:长度为0的位段的作用是使下一个位段的内容从新的存储单元开始存放。要点:注意每个字段的最

22、大取值范围.如:data.a的取值只能是:03,因为两位二进制最大表示的数为3.方法:通过结构体成员来应用:如:data.a=2;data.b=6;,struct packunsigned a:2;unsigned:0;unsigned b:4;unsigned c:4;int x;data;,1.6.2 位域的使用,位域的使用要点位段可以用十进制的整型形式输出,也可以用其他的整型格式输出(如八进制,十六进制和无符号),位段以整型的形式参加算术运算.分析下面的程序:,main()struct pack unsigned a:2;unsigned b:3;unsigned c:1;unsigne

23、d d:4;unsigned e:3;unionstruct pack qp;unsigned i;abc;abc.i=255;printf(“%dn”,abc.qp.d);,1.6.2 位域的使用,位域的使用例子,main()struct bs unsigned a:1;unsigned b:3;unsigned c:4;bit,*pbit;bit.a=1;bit.b=7;bit.c=15;printf(%d,%d,%dn,bit.a,bit.b,bit.c);pbit=,1.7 其他预处理关键字,#error 使用defined#line#pragma#和#预定义宏,1.7.1#error

24、,#error指令强制编译程序停止编译,主要用于程序调试#error指令的一般形式是#error error-message注意:宏串error-message不用双引号包围 可以自定义错误内容,1.7.2 使用defined,确定是否定义宏名字的方法 defined操作符的一般形式如defined macro-name define与ifdef:#if defined MY或#ifdef MY感叹号”!”来反转相应的条件#if!defined DEBUG Printf(“Final Version!n”);#endif,1.7.3#line,#line指令改变_LINE_和_FILE_的内容

25、#line的一般形式#line number“filename”主要用于调试和特殊应用,1.7.5#和#,操作符#通常称为字符串化的操作符 预处理程序把以下的语句:Printf(mkstr(I like C);变成 Printf(“I like C”);,#include#define mkstr(s)#sint main(void)Printf(mkstr(I like C);Return 0;,1.7.5#和#,“#”可以把两个独立的字符串连接成一个字符串,#include#define SORT(X)sort_function#Xvoid main(void)char*array;int

26、 elements,element_size;SORT(3)(array,elements,element_size);,结果:SORT(3)转化为sort_function3 SORT(3)(array,elements,element_size)转化为 sort_function3(array,elements,element_size,1.7.6 预定义宏,_DATE_ 进行预处理的日期(“Mmm dd yyyy”形式的字符串文字)_FILE_ 代表当前源代码文件名的字符串文字_LINE_ 代表当前源代码中的行号的整数常量_TIME_ 源文件编译时间,格式微“hh:mm:ss”_func

27、_ 当前所在函数名,1.7.6 预定义宏,例子,#include#include void why_me();int main()printf(The file is%s.n,_FILE_);printf(The date is%s.n,_DATE_);printf(The time is%s.n,_TIME_);printf(This is line%d.n,_LINE_);printf(This function is%s.n,_func_);why_me();return 0;,void why_me()printf(This function is%sn,_func_);printf(

28、The file is%s.n,_FILE_);printf(This is line%d.n,_LINE_);,阶段小节,位操作几个运算操作的特点位段的特点和位段数据的引用位段使用的规则C语言扩展宏定义几个具体应用调试与!define,本章结构,编译预处理,编译预处理和位运算,位段,文件包含,宏定义,条件编译,位运算,预处理其他关键词,预处理的基础操作方式,define定义的原则和注意事项及应用,讲述文件包含的特点和用处,以及include”和的区别,讲述条件编译的三种应用方式和主要功能实现,了解位运算的基本操作,重点在与和或运算,了解位段的基本定义,讲述了error以及pragma和调试输入基本应用,本章总结,宏定义特点和注意细节条件编译特点和主要用处文件包含的路径查询规则位操作运算的几个具体运用C语言扩展宏定义的用法,实验1,题目用宏定义来实现两个数取最大值注意事项?运算符的运用对参数的包含define的语法特点实验结果掌握宏定义的具体应用,深化对宏定义的操作。,实验2,题目从键盘上输入1 个正整数给int 变量num,按二进制位输出该数,同时分别对第五位取反,第六位置一,第七位清零注意事项键盘输入操作特点位操作的运算用宏定义实现位操作CLEARSETTINGREVER实验结果熟悉位操作基本运算,同时为以后嵌入式数据操作提供基础程序编码。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号