版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第八章C语言程序设计主要内容存储器区域数据类型类型限定符存储类别绝对位置变量指针函数属性预处理器内嵌汇编程序定制文件设计实例:按键识别与显示存储器区域STC32G系列单片机兼容MCS-251ISA,因此支持用于程序和数据的多个物理分离的存储区域或存储器空间每个存储区域都有一定的优点和缺点这些存储空间可能是读取但不写入、读取或写入、比其他存储空间更快地读取或写入STC32G系列单片机上可用的各种存储空间与大多数大型计算机、小型寄存器和微型计算机架构有很大的不同在这些架构中,程序、数据和常数都加载到计算机内的同一物理存储空间存储器区域
--程序存储器程序(CODE)存储器为只读。在STC32G系列单片机中,程序存储器位于单片机的内部该单片机支持高达64KB的程序存储器。然而,可以使用代码库来扩展程序空间
一些单片机提供了更大的代码空间
程序代码,包含所有函数和库例程,保存在程序存储器中
常数变量也可以保存在程序存储器中STC32G系列仅执行保存在程序存储器中的程序
通过使用存储器类型标识符code,C语言程序可以访问程序存储器
声明code对象的用法如下:unsignedcharcodecode_constant;存储器区域
--程序存储器声明code对象的用法如下:unsignedcharcodecode_constant;注:存储器类型code是为了与C51编译器兼容而实现的。应该使用constnear或constnear代替代码。这通常会生成更好的代码,应该在新的STC32G系列单片机中使用,而不是存储器类型code存储器区域
--内部数据存储器内部数据存储器位于STC32G系列单片机的内部,并且是读/写的data和idata存储区域位于STC32G系列单片机内,并且可以写入和读取data存储器是片上存储器的前128字节。idata存储器是片上存储器的前256个字节。还有一个从20h开始的16字节区域,可用短8051兼容指令进行位寻址声明idata变量的方法如下:unsignedcharidatavariable;对内部数据存储器的访问非常快,因为它可以使用8位地址访问。然而,内部数据存储器限制为最大256字节存储器区域
--内部数据存储器内部数据存储器可以分为三种不同的数据类型,包括databdataebdata存储器区域
--内部数据存储器存储器说明符data是指内部数据存储器的前128个字节此处保存的变量使用直接寻址进行访问声明data变量,如下所示:unsignedchardatafast_variable;存储器区域
--内部数据存储器存储器说明符bdata指定的内部数据区(20h~2Fh)中的16字节可位寻址的存储器该存储器类型说明符允许程序开发人员声明也可以在位级别访问的数据类型声明bdata变量,如下所示:unsignedcharbdatabdata_var;存储器区域
--内部数据存储器存储器说明符ebdata是指内部数据区(20h~7Fh)中的扩展251位可寻址存储器该存储器类型说明符允许程序开发人员声明也可以在位级别访问的数据类型然而,与bdata存储区域相比,对ebdata存储器的位访问需要更长的操作码编码声明edata变量,如下所示:unsignedintebdataeb_var;存储器区域
--内部数据存储器【例8-1】存储器说明符ebdata的用法structs{//定义结构体sunsignedintb0:3;//整型变量b0,分配3个二进制位unsignedintb1:2;//整型变量b1,分配2个二进制位unsignedintb2:1;//整型变量b2,分配1个二进制位unsignedintb3:1;//整型变量b3,分配1个二进制位unsignedintb4:1;//整型变量b4,分配1个二进制位unsignedintb5:1;//整型变量b5,分配1个二进制位unsignedintb6:1;//整型变量b6,分配1个二进制位unsignedintb7:4;//整型变量b7,分配4个二进制位};存储器区域
--内部数据存储器structsebdatav;//声明结构体变量v,且保存在ebdata区域
voidmain(void){//声明主程序main v.b0=4;//结构变量v的元素b0赋值为4 v.b1=3;//结构变量v的元素b1赋值为3 v.b7=15;//结构变量v的元素b7赋值为15if(v.b1){//如果结构变量v的元素b1的值不为0v.b0=7;//结构变量v的元素b0赋值为7}}存储器区域
--内部数据存储器对于上面的设计代码,变量的位分配位号0x20.70x20.60x20.50x20.40x20.30x20.20x20.10x20.0变量——v.b7v.b6v.b5位号0x21.70x21.60x21.50x21.40x21.30x21.20x21.10x21.0变量v.b4v.b3v.b2v.b1v.b0存储器区域
--内部数据存储器0xFF0000020030LJMPC:0x003014:voidmain(void){15:v.b0=4;0xFF00037E3520MOVWR6,v(0x20)0xFF00065E70F8ANLR7,#0xF80xFF00094E7004ORLR7,#0x04//R7[3:0]=0x040xFF000C7A3520MOVv(0x20),WR6//{R6,R7}=WR616:v.b1=3;0xFF000F4E7018ORLR7,#0x18//
0x18逻辑“或”R7,R7.4,R7.3置10xFF00127A3520MOVv(0x20),WR6//17:v.b7=15;0xFF00154E603CORLR6,#0x3C0xFF00187A3520MOVv(0x20),WR6
存储器区域
--内部数据存储器18:if(v.b1){0xFF001B7D23MOVWR4,WR60xFF001D1E24SRLWR40xFF001F1E24SRLWR40xFF00211E24SRLWR40xFF00235E240003ANLWR4,#0x00030xFF00276806JEC:0x002F19:v.b0=7;0xFF00294E7007ORLR7,#0x070xFF002C7A3520MOVv(0x20),WR620:}存储器区域
--外部数据存储器片内/片外的外部数据存储器是读/写的由于外部数据存储器是通过数据指针寄存器(必须加载地址)间接访问的,因此它比访问内部数据存储器慢STC32G系列单片机提供了片上XRAM空间,该空间使用与传统外部数据空间相同的指令进行访问。该XRAM空间通常通过配置SFR寄存器启用,并于外部存储器空间重叠可能有多达64KB的外部数据存储器。然而,该地址空间不一定必须用作存储器。硬件设计可能会将外设映射到存储器空间中。如果是这种情况,开发的程序将访问外部数据存储器来编程和控制外设。这种技术称为存储器映射的I/Osfr80H~FF,PWM,USB,….声明xdata变量的方法如下:unsignedcharxdatavariable;存储器区域
--近存储器近存储器(nearmemory)区域的地址范围为00:0000~00:FFFF,这是STC32G系列单片机存储器的前64KB部分寄存器位于STC32G系列单片机的内部,并且可以使用16位寻址进行快速的访问近存储器区域在汇编语言级别由存储器类EDATA或ECONST表示,使用直接寻址访问保存在近存储器中的变量声明near对象的方法如下:unsignedcharnearnear_variable;unsignedcharconstnearnear_const_variable;存储器区域
--远存储器远存储器(farmemory)区域表示STC32G系列单片机的完整地址范围远存储器区域在汇编语言级别中使用存储器类HDATA或HCONST表示使用间接寻址来访问存储器类型far定义的变量地址计算仅为16位,因此将远对象的数据大小限制为64KB然而,远变量可以驻留在存储器中的任何位置,这允许总大小多达16MB存储器区域
--远存储器声明far对象的方法如下:unsignedcharfarfar_variable[0x10000];unsignedcharconstfarfar_const_variable[0x4000]={1,2,3,...};unsignedinti;unsignedcharfar_func(void){return(far_variable[i]);}存储器区域
--大存储器与far相反,huge使用32位运算进行地址计算,因此允许无限的对象大小程序开发人员可以有一个数MB大小的单个数组或结构在大存储器(hugememory)中,声明的变量的大小可以达到16MB-1存储器区域
--大存储器声明huge对象的方法如下:unsignedcharhugehuge_variable[0x50000];unsignedcharconsthugehuge_const_variable[0x20000]={1,2,3,...};unsignedlongl;unsignedintfunction(void){return(huge_variable[l]);}存储器区域
--SFR存储器STC32G系列单片机为SFR提供128字节的存储器SFR是位、字节或字大小的寄存器,用于控制定时器、计数器、串行I/O和外设注:可以使用MOV指令直接访问SFR存储器,不能使用间接寻址模式数据类型C251编译器提供了几种可以在C程序中使用的基本数据类型编译器支持标准C数据类型以及MCS-251ISA特有的几种数据类型数据类型位数字节数值的范围bit1—“0”或“1”signedchar81-128~+127unsignedchar810~+255enum162-32768~+32767signedshortint162-32768~+32767unsignedshortint1620~+65535数据类型数据类型位数字节数值的范围signedint162-32768~+32767unsignedint1620~+65535signedlongint324-2147483648~+2147483647unsignedlongint3240~+4294967295float324±1.17549435E-38~±3.4028235E+38double648±2.2250738585072014E-308~±1.7976931348623158E+308idata,data,pdata(指针)810~0Xffnear,xdata,code(指针)1620~0xFFFF数据类型far,huge(指针)3240~0Xffffffsbit1—“0”或“1”sfr810~+255sfr161620~+65535数据类型位数字节数值的范围数据类型
--标准C语言所支持的类型本节只介绍标准C语言所支持数据类型中的基本类型,包括voidcharintenumfloatdouble标准C语言所支持的类型
--void数据类型void定义了没有返回值的函数,没有参数列表的函数以及指向未定义类型对象的指针其用法如下:voidfunction-name(argument-list);return-typefunction-name(void);void*name;其中function-name为函数的名字argument-list为传给函数的参数return-type为函数的返回类型name为指向void对象的指针标准C语言所支持的类型
--char数据类型char定义了1个字节的二进制整数其格式为:<[>{signed|unsigned}<]>charname<[>=value<]>;其中name为变量的名字value为分配给变量的值signed或unsigned显式声明数据类型是有符号或无符号标准C语言所支持的类型
--int数据类型int定义了1个二进制整数其格式为:
<[>{signed|unsigned}<]><[>{long|short}<]>intname<[>=value<]>;其中name为变量的名字value为分配给变量的值signed或unsigned显式声明数据类型是有符号的还是无符号的long或short声明整数是32位或16位的整数标准C语言所支持的类型
--enum关键字enum(枚举)定义了一组int类型的常数其格式如下:enum[tag]{name[=value],...};其中tag为enum集的名字name为枚举常数的名字value为分配给常数的值。如果缺少值,则假定它是集合+1中的前一个常量的值。列表中第一个常数的默认值为0标准C语言所支持的类型
--float数据类型float定义了IEEE-754浮点数其格式如下:floatname<[>=value<]>;其中name为变量的名字value为分配给变量的值标准C语言所支持的类型
--float在兼容MCS-251ISA的STC32G系列单片机中,浮点数按下面格式保存表中s表示符号位,取值为“1”表示负数,“0”表示正数E是指数M是24位尾数(保存23位)。最高位24位总是为“1”,因此无需保存地址地址+0地址+1地址+2地址+3内容SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM标准C语言所支持的类型
--float浮点数-12.5,其保存在STC32G系列单片机中保存为十六进制数0xC1480000该十六进制数在存储器中的保存格式表中:符号位为“1”,表示该浮点数为负数指数为“10000010”,等效于十进制数130尾数为“10010000000000000000000”,等效于十进制小数0.5625地址地址+0地址+1地址+2地址+3内容(十六进制)0xC10x480x000x00内容(二进制数)11000001010010000000000000000000标准C语言所支持的类型
--float
因此,真正的十进制浮点数表示为:注:STC32G系列单片机中不包含捕获浮点错误的中断向量。因此,软件必须对这些错误条件进行适当的响应
标准C语言所支持的类型
--floatC251库函数_chkfloat_允许程序开发人员快速的检查浮点状态作为替代方案,可以使用下面的联合体来保存浮点值unionf{floatf;//浮点数的值unsignedlongul;//无符号长整型数};该联合体包含一个浮点数和一个无符号长整型数,用于执行浮点运算以及响应IEEE的错误状态标准C语言所支持的类型
--float检查浮点运算状态的C语言代码#include<intrins.h>//包含头文件intrins.h#include<stdio.h>//包含头文件stdio.h#include<reg251s.h>//包含头文件reg251s.h
voidmain(void)//主函数main{ floatf2=1.0,f3=0.0;//声明浮点数f2和f3floatf1;//声明浮点数f1SCON=0x52;//初始化串口寄存器SCONTMOD=0x20;//初始化串口寄存器TMODTCON=0x69;//初始化串口寄存器TCONTH1=0xF3;//初始化串口寄存器TH1 f1=f2/f3;//浮点数f2和f3相除,除数f3为0标准C语言所支持的类型
--floatswitch(_chkfloat_(f1))//调用chkfloat,判断浮点运算结果 {case0://取值为0,表示浮点运算结果正常printf("resultisanumber\n");break;//在KeilUART窗口打印信息case1://取值为1,表示浮点除数为零printf("resultiszero\n");break;//在KeilUART窗口打印信息case2://取值为2,表示浮点运算上溢printf("resultis+INF\n");break;//在KeilUART窗口打印信息case3://取值为3,表示浮点运算下溢printf("resultis-INF\n");break;//在KeilUART窗口打印信息case4://取值为4,表示不是一个数printf("resultisNaN\n");break;//在KeilUART窗口打印信息}}标准C语言所支持的类型
--double数据类型double定义了IEEE-754浮点数其格式如下:doublename<[>=value<]>;其中name为变量的名字value为分配给变量的值注:只要没有使用FLOAT64编译器命令,数据类型double和数据类型float就是相同的。在这种情况下,类型double的变量使用与类型float相同的4字节存储类型标准C语言所支持的类型
--double数据类型
--位寻址对象位可寻址对象是可以作为字或者位寻址的对象只有占据STC32G系列单片机内部存储器的位可寻址区域的数据对象属于这一类别C251编译器将用bdata或ebdata存储器类型声明的变量放到位可寻址区域存储器类型bdata是指8051兼容位空间;ebdata指定扩展的STC32G系列单片机的位空间bdata和ebdata存储器类型都像数据存储器类型一样处理,除了变量驻留在片上数据存储器的位可寻址部分中注:对于bdata,该存储器区域的总大小不能超过16字节;对于ebdata,则不能超过96字节数据类型
--位寻址对象程序开发人员可以声明全局bdata/ebdata变量,如下所示:intbdataibase;//位可寻址的int型charbdatabary[4];//位可寻址的数组intebdataibase;//ebdata可位寻址的int型charebdatabary[4];//ebdata可位寻址的char型上面的例子中,变量ibase和bary是可位寻址的。因此,可以直接访问和修改这些变量的各个位。使用sbit关键字声明访问bdata变量位的新变量sbitmybit0=ibase^0;//ibase的位0sbitmybit15=ibase^15;//ibase的位15数据类型
--位寻址对象sbitAry07=bary[0]^7;//bary[0]的位7sbitAry37=bary[3]^7;//bary[3]的位7
sbitebBit0=ebase^0;//ebase的位0sbitebBit15=ebase^15;//ebase的位15
sbitebAry07=eary[0]^7;//eary[0]的位7sbitebAry37=eary[3]^7;//eary[3]的位7数据类型
--位寻址对象上面的例子表示声明,而不是对ibase/ebase和bary/eary变量的位的赋值例子中的符号“^”后面的表达式指定使用该声明访问的位的位置。该表达式必须是常数值范围取决于声明中包含的基变量的类型。范围是:0~7用于char和unsignedchar;0~15用于int、unsignedint、short和unsignedshort;0~31用于long和unsignedlong;注:C251编译器假设使用sbit声明访问的对象以小端字节顺序保存。这是sfr16类型的情况。然而,像int和long这样的标准C类型以大端保存数据类型
--位寻址对象此外,可以为sbit类型提供外部变量声明,以访问其他模块中的这些类型。例如:externbitmybit0;//ibase的位0externbitmybit15;//ibase的位15
externbitAry07;//bary[0]的位7externbitAry37;//bary[3]的位7
externbitebdataeBit15;//外部基于ebdata的位externbitebdataebAry37;//外部基于ebdata的位数据类型
--位寻址对象涉及sbit类型的声明要求使用存储器类型bdata或ebdata声明基对象注:基于ebdata的外部位的声明需要存储器类型ebdata。如果没有显式存储器,则假定默认空间bdata唯一例外的是特殊功能位的“变种”。如果要声明基于SFR的位,则必须省略存储器空间下面的例子说明了基于上述声明更改ibase和bary位的方法Ary37=0;//清除bary[3]的位7bary[3]='a';//字节寻址ibase=-1;//字寻址mybit15=1;//设置ibase的位15数据类型
--位寻址对象除了用bdata声明的变量位于内部数据存储器的可位寻址部分之外,bdata存储器类型的处理方式于数据存储器类似注:该存储器区域的总大小不能超过16字节数据类型
--位寻址对象除了位标量类型声明sbit变量之外,还可以为结构和联合声明sbit。比如:unionlft//声明联合类型lft{floatmf;longml;};sbittcpf31=tcp.u.ml^31;//浮点位31sbittcpm10=tcp.m1^0;//字符位0sbittcpm17=tcp.m1^7;//字符位7数据类型
--位寻址对象bdatastructbad//声明结构类型bad,设置在bdata区域
{charm1;unionlftu;}tcp;数据类型
--位寻址对象bit类型定义单个位变量。其用途如下:bitname<[>=value<]>其中:name为位变量的名字value为分配给位变量的值bit类型可用于变量声明、参数列表和函数返回值数据类型
--位寻址对象位变量和其他C数据类型一样声明。例如:staticbitdone_flag=0;//声明并初始化位变量done_flag
//函数testfunc返回类型为bit,参数类型为bitbittestfunc(bitflag1,bitflag2){…return(0);//函数返回类型为bit}数据类型
--位寻址对象所有的位变量都保存在STC32G系列单片机的8051兼容内部存储器区域中的位段中因为该区域只有16个字节长度,所以在任何一个范围内最多可以声明128位变量注:对STC32G系列单片机的扩展位的访问比对标准8051兼容位区域的访问产生更多的代码。因此,程序开发人员应尽可能使用标准的8051兼容位区域,以最大化性能数据类型
--位寻址对象STC32G系列单片机支持位于数据存储器地址范围0x20~0x7F中扩展位可寻址区域。该区域最多支持768位变量要在扩展位区域中定位位,需要指定ebdata。如下所示:bitebdatastate1;//在扩展位空间声明位变量state1bitfunction(bitflag)//在8051位空间的位参数flag{bitebdatalocal_bit;//在扩展位空间声明本地位变量local_bitlocal_bit=flag;return(local_bit);//函数返回扩展位空间位变量local_bit}数据类型
--位寻址对象下面的限制适用于位变量和位声明:不能将位声明成指针。例如:bit*ptr;//非法的位类型的数组无效。例如:bitware[5];//非法的
禁止中断的函数(#pragmadisable)和使用显式寄存器声明的函数(usingn)不能返回类型为bit的值C251编译器为尝试返回位类型的此类函数生成错误消息数据类型
--特殊功能寄存器STC32G系列单片机位访问SFR提供了独特的存储区域在程序中,SFR用于控制定时器、计数器、串行I/O、端口I/O和外设SFR位于地址0x80~0xFF之间,可以作为位、字节和字访问特殊功能寄存器
--sfrsfr类型定义了一个SFR其格式如下:sfrname=address;其中name为SFR的名字address为SFR的地址SFR的声明方式与其他C变量相同。唯一的区别是指定的类型是sfr而不是char或int特殊功能寄存器
--sfr例如:sfrP0=0x80;//端口0的地址为80hsfrP1=0x90;//端口1的地址为90hsfrP2=0xA0;//端口2的地址为0A0hsfrP3=0xB0;//端口3的地址为0B0hP0、P1、P2和P3是SFR名字声明sfr变量的名字与其他C变量声明一样定义sfr声明中可以使用任何符号名字等号(“=”)后面的地址规范必须是数字常数。不允许使用带有运算符的表达式。此常数表达式必须位于SFR地址范围(0x80~0xFF)内。注:不能在函数中声明sfr变量,它必须在函数体之外声明特殊功能寄存器
--sfr16sfr16类型定义了一个16位SFR其格式如下:sfr16name=address;其中:name为16位SFR的名字address为16位SFR的地址STC32G系列单片机中具有16位的SFR,这些SFR是使用SFR存储器中连续的地址创建的,以指定16位的值其余规则同sfr的声明特殊功能寄存器
--sbitbit类型定义SFR中的一位其格式如下:sbitname=sfr-name^bit-position;sbitname=sfr-address^bit-position;sbitname=sbit-address;其中:name为SFR位的名字sfr-name为之前定义的sfr的名字bit-position为SFR内位的位置sfr-address为SFR的地址sbit-address为SFR位的地址特殊功能寄存器
--sbit对于基于STC32G系列单片机的应用程序,通常需要访问SFR内的各个位sbit类型提供对位可寻址SFR以及其他位可选址对象的访问例如:sbitEA=0xAF;该声明将EA定义为地址0xAF的SFR位。在STC32G系列单片机中,这是中断使能寄存器中的使能控制位特殊功能寄存器
--sbit在sbit声明中,可以使用任何符号名字等号(‘=’)右侧的表达式为符号名字指定绝对位地址指定地址有三种可变的形式:特殊功能寄存器
--sbitsbitname=sfr-name^bit-position;之前声明的SFR(SFR名字)是sbit的基地址。它必须能被8整除。比特位置(必须是0~7之间的数字)跟随着符号‘^’,并指定要访问的比特位置,比如:sfrPSW=0xD0;sfrIE=0xA8;
sbitOV=PSW^2;sbitCY=PSW^7;sbitEA=IE^7;特殊功能寄存器
--sbitsbitname=sfr-address^bit-position;字符常数(sfr地址)指定sbit的基地址。它必须能被8整除比特位置(必须是0~7之间的数字)跟随‘^’,并指定要访问的比特位置。例如:sbitOV=0xD0^2;sbitCY=0xD0^7;sbitEA=0xA8^7;特殊功能寄存器
--sbitsbitname=sbit-address;字符常数(sbit地址)指定sbit的地址。它必须是0x80~0xFF之间的值。比如:sbitOV=0xD2;sbitCY=0xD7;sbitEA=0xAF;特殊功能寄存器
--sbit需要注意以下的一些限制条件:并非所有SFR都是位可寻址的只有地址可被8整除的SFR才是位可寻址的特殊功能位表示一个独立的声明类,它不能与其他位声明或位字段互换sbit数据类型声明可用于访问使用bdata内存类型说明符声明的变量的各个位第八章C语言程序设计类型限定符C251编译器支持两个类型限定符,包括const和volatileconst类型限定符声明了一个在运行时未修改的对象volatile类型限定符声明了一个对象,该对象的值可能会被出现在其中的代码之外的某个对象修改在嵌入式系统中,这通常是硬件类型限定符
--const在ANSIC中,const类型限定符用于定义和访问常数且不能更改的对象用const声明的变量不能在程序中赋值仅用const类型限定符声明的变量保存在与其定义相关联的存储器区域(data、idata、xdata等)中constunsignedshortxdataa[10]={0,1,2,3,4,5,6,7,8,9};需要在ROM中定位的变量必须用code存储器类型声明constunsignedshortcodea[10]={0,1,2,3,4,5,6,7,8,9};类型限定符
--const常数对象通常在定义(在源文件中)时初始化下面的变量定义显示了创建常数对象的不同方法:constinttable[2][2]={0,2,4,8};//table保存在默认的存储器类中constfloatfarpi=3.1415926;//pi保存在HCONST存储器类中printf(“Thisisastring\n”);//字符串保存在HCONST存储器类中类型限定符
--const当使用指向const对象的指针时,可以在指针定义中排除const类型限定符,例如:constunsignedcharmask[]={0x01,0x02,0x04,0x08};constunsignedchar*cp=mask;unsignedchar*p=mask;//与cp效果相同………*p=’a’;//这里没效果,不会导致警告或错误*cp=’a’;//这会导致错误从上面可知,可以将常数对象mask的地址分配给非常数的指针p,然后使用该指针更改常数对象。在这种情况下,编译器会生成代码写入常数对象。该代码的效果未定义,可能或无法按预期工作不能使用const指针来更改它指向的常数对象。如果这样做,将导致编译器错误类型限定符
--constconst的一个有趣的用法是定义一个不可更改的指针例如:chartext[]=”Thisisastring“;char*consttextp=text;…………*textp=’A‘;//这是正常的(它会改变test[0])textp++;//这会导致错误(textp为常数)textp[2]=’B’;//这是正常的(它会改变test[2])类型限定符
--volatile易失性类型限定符用于限制编译器对对象值的假设例如:unsignedcharreg1;//硬件寄存器#1unsignedcharreg2;//硬件寄存器#2
voidfunc(void){while(reg1&0x01)//当设置位0时,重复{reg2=0x00;//轮询位7reg2=0x80;}}类型限定符
--volatile该程序使用两个变量(reg1和reg2)访问硬件寄存器在大多数情况下,编译器将reg1加载到寄存器中,并且不会在循环迭代之间重新读取它(即使硬件寄存器可能正在更改)此外,对reg2的三个赋值可以简单的优化为最终的赋值(前两个赋值不生成代码)。这些影响是由优化器造成的,而不是编译器生成的错误事实上,这些是编译器应该进行的优化类型。然而,在这种情况下,它们肯定是不可取的类型限定符
--volatile因此,引入volatile类型限定符来解决以上的问题。比如:volatileunsignedcharreg1;//硬件寄存器#1volatileunsignedcharreg2;//硬件寄存器#2
voidfunc(void){while(reg1&0x01)//当设置位0时,重复{reg2=0x00;//轮询位7reg2=0x80;}}通过将reg1和reg2定义为volatile,编译器现在知道对这些变量的访问可能不会被优化。生成的代码按需要执行类型限定符
--volatile【例8-3】不同数据类型运算的C语言描述voidmain(){ volatilecharedataa=100,b=-90,c;//edata空间放置字符变量volatileintedatad=10000,e=-5000,f;//edata空间放置字变量//edata空间放置双字变量volatilelongintedatah=20000000,i=-10000000,j; volatilebitebdatax=1,y=1,z,w;//ebdata空间放置位变量c=a+b;//字符变量a和b相加 f=d+e;//字变量d和e相加 j=h+i;//双字变量h和i相加 z=x&y;//位变量x和y逻辑“与”w=x^y;//位变量x和y逻辑“异或”}类型限定符
--volatile该C语言代码对应的反汇编代码1:voidmain()2:{3:volatilecharedataa=100,b=-90,c;0xFF00037464MOVA,#0x640xFF00057AB30008MOVa(0x0008),R110xFF000974A6MOVA,#0xA60xFF000B7AB30009MOVb(0x0009),R114:volatileintedatad=10000,e=-5000,f;0xFF000F7E342710MOVWR6,#0x27100xFF00137A37000BMOVd(0x000B),WR60xFF00177E34EC78MOVWR6,#0xEC780xFF001B7A37000DMOVe(0x000D),WR6类型限定符
--volatile
5:volatilelongintedatah=20000000,i=-10000000,j;0xFF001F7E342D00MOVWR6,#0x2D000xFF00237E240131MOVWR4,#0x01310xFF00277A1F0011MOVh(0x0011),DR40xFF002B7E346980MOVWR6,#0x69800xFF002F7E24FF67MOVWR4,#0xFF670xFF00337A1F0015MOVi(0x0015),DR46:volatilebitebdatax=1,y=1,z,w;0xFF0037A9D020SETBx(0x20.0)0xFF003AA9D120SETBy(0x20.1)类型限定符
--volatile7:c=a+b;0xFF003D7E730009MOVR7,b(0x0009)0xFF00411A27MOVSWR4,R70xFF00437E730008MOVR7,a(0x0008)0xFF00471A37MOVSWR6,R70xFF00492D32ADDWR6,WR40xFF004B7A73000AMOVc(0x000A),R78:f=d+e;0xFF004F7E37000DMOVWR6,e(0x000D)0xFF00532E37000BADDWR6,d(0x000B)0xFF00577A37000FMOVf(0x000F),WR6类型限定符
--volatile9:j=h+i;0xFF005B7E0F0015MOVDR0,i(0x0015)0xFF005F7E1F0011MOVDR4,h(0x0011)0xFF00632F10ADDDR4,DR00xFF00657A1F0019MOVj(0x0019),DR410:z=x&y;0xFF0069A9A120MOVC,y(0x20.1)0xFF006CA98020ANLC,x(0x20.0)0xFF006FA99220MOVz(0x20.2),C类型限定符
--volatile11:w=x^y;0xFF0072A9A120MOVC,y(0x20.1)0xFF0075A9302001JNBx(0x20.0),C:0x007A0xFF0079B3CPLC0xFF007AA99320MOVw(0x20.3),C12:}类型限定符
--volatile【例8-4】浮点数运算的实现(一)voidmain(){volatilefloata=100.0,b=200.0; volatilefloatedatac=a+b;}类型限定符
--volatile该C语言代码对应的反汇编代码1:voidmain()2:{3:volatilefloata=100.0,b=200.0;0xFF01126D33XRLWR6,WR60xFF01147E2442C8MOVWR4,#0x42C80xFF01187A1F0008MOVa(0x0008),DR40xFF011C7E244348MOVWR4,#0x43480xFF01207A1F000CMOVb(0x000C),DR4类型限定符
--volatile4:volatilefloatedatac=a+b;5:0xFF01247E0F000CMOVDR0,b(0x000C)0xFF01287E1F0008MOVDR4,a(0x0008)0xFF012C120009LCALLC?FPADD(C:0x0009)0xFF012F7A1F0010MOVc(0x0010),DR46:}类型限定符
--volatile【例8-5】浮点数运算的实现(二)voidmain(){floata=100.0,b=200.0; volatilefloatedatac=a+b;}类型限定符
--volatile该C语言代码对应的反汇编代码1:voidmain()2:{3:floata=100.0,b=200.0;4:volatilefloatedatac=a+b;0xFF00196D33XRLWR6,WR60xFF001B7E244396MOVWR4,#0x43960xFF001F7A1F0008MOVc(0x0008),DR45:}类型限定符
--volatile【例8-6】数组元素存储和运算的C语言代码voidmain(){constcharcodetable[]={1,2,4,8}; volatilechari=0,sum=0; for(i=0;i<4;i++)sum+=table[i];}类型限定符
--volatile该C语言代码对应的反汇编代码1:voidmain()2:{3:constcharcodetable[]={1,2,4,8};4:volatilechari=0,sum=0;0xFF0003E4CLRA0xFF00047AB30008MOVi(0x0008),R110xFF00087AB30009MOVsum(0x0009),R115:for(i=0;i<4;i++)0xFF000C8021SJMPC:0x002F类型限定符
--volatile
6:sum+=table[i];0xFF000E7E730008MOVR7,i(0x0008)0xFF00121A37MOVSWR6,R70xFF00142E340053ADDWR6,#0x00530xFF00187A7182MOVDPL(0x82),R70xFF001B7A6183MOVDPH(0x83),R60xFF001EE4CLRA0xFF001F93MOVCA,@A+DPTR0xFF00207C7BMOVR7,R110xFF00222E730009ADDR7,sum(0x0009)0xFF00267A730009MOVsum(0x0009),R7类型限定符
--volatile0xFF002A7EB30008MOVR11,i(0x0008)0xFF002E04INCA0xFF002F7AB30008MOVi(0x0008),R110xFF00337E730008MOVR7,i(0x0008)0xFF0037BE7004CMPR7,#0x040xFF003A48D2JSLC:0x000E7:}存储类别C语言支持许多可以应用于程序变量的存储类存储类用于定义变量和函数的范围和生存周期,这些存储类关键字包括:autoregisterstaticextern存储类别
--autoauto存储类是本地变量默认的存储类其格式如下:autodata-typename<[>=value<]>其中data-type为变量的数据类型name是变量的名字value是分配给变量的值需要注意,存储类auto只能在函数定义内使用存储类别
--registerregister存储类定义了应该保存在一个或多个寄存器中而不是RAM中的局部变量其格式如下:registerdata-typename<[>=value<]>;其中data-type为变量的数据类型name为变量的名字value为分配给变量的值通常,C251编译器忽略register存储类。如果有可能,所有变量都保存在寄存器中注:存储类register只能在函数定义内使用存储类别
--staticstatic存储类限制变量的范围并修改局部变量的生存期其格式如下:staticdata-typename<[>=value<]>;其中data-type为变量的数据类型name为变量的名字value是分配给变量的值使用static在函数外部声明变量时,无法在声明变量的源文件外部访问该变量当使用static在函数内部声明变量时,该变量在启动时就被初始化(与其他全局变量一样),并且在调用该函数时保留其值在进入函数时,它不会被重新初始化存储类别
--externextern存储类声明在另一个源模块中定义的全局变量其格式如下:externdata-namename;其中data-type为变量的数据类型name为变量的名字当使用extern声明变量时,无法初始化该变量,这是因为它已经在定义的位置初始化了存储类别【例8-7】存储类用法的C语言描述
在extern.c文件中定义变量shortinta=3000,b=-2000;
在main.c文件中调用外部变量#include"math.h"externshortinta,b;voidmain(){volatilelongintc; c=a*b;}存储类别该C语言代码对应的反汇编代码
3:voidmain()4:{5:volatilelongintc;6:c=a*b;0xFF00427E17000AMOVWR2,b(0x000A)0xFF00461A02MOVSWR0,R20xFF00481A00MOVSWR0,R00xFF004A7E370008MOVWR6,a(0x0008)0xFF004E1A26MOVSWR4,R60xFF00501A24MOVSWR4,R40xFF005212005ALCALLC?LMUL(C:0x005A)0xFF00557A1F000CMOVc(0x000C),DR47:}存储类别有符号乘法运算的算法C?LMUL:0xFF005A7D51MOVWR10,WR20xFF005CAD03MULWR0,WR60xFF005E7D02MOVWR0,WR40xFF00607D21MOVWR4,WR20xFF0062AD05MULWR0,WR100xFF00642D12ADDWR2,WR40xFF0066AD35MULWR6,WR100xFF00682D21ADDWR4,WR20xFF006A22RET存储类别【例8-8】static关键字的C语言用法inti=0;//声明全局变量iintcal(intx)//定义函数cal,形参x{ staticinty=0;//定义局部静态变量yy=x-y-i;//x-y-i→y,由于y为静态变量,y的结果被保存returny;//返回y值}
存储类别voidmain()//定义main主函数{ intj=1000;//定义并初始化本地局部变量j i=cal(j);//第一次调用函数cal i=cal(j);//第二次调用函数cal i=cal(j);//第三次调用函数cal}存储类别
9:voidmain()10:{11:intj=1000;12:i=cal(j);0xFF00427E3403E8MOVWR6,#0x03E80xFF0046120064LCALLcal(C:0x0064)0xFF00497A370008MOVi(0x0008),WR613:
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025宁夏伊品生物科技股份有限公司招聘16人笔试历年参考题库附带答案详解
- 2025四川酒业集团有限责任公司下属子公司招聘62人笔试历年参考题库附带答案详解
- 2025四川九洲防控科技有限责任公司招聘党建干事等岗位36人笔试历年参考题库附带答案详解
- 2025北京上庄燃气热电有限公司招聘生产管理部热控主管笔试历年参考题库附带答案详解
- 2025内蒙古新太实业集团有限公司校园招聘30名笔试历年参考题库附带答案详解
- 2025中车青岛四方车辆研究所有限公司实习生招聘(30人)笔试历年参考题库附带答案详解
- 2025中国少年儿童新闻出版总社有限公司社会人员招聘30人笔试历年参考题库附带答案详解
- 2025上半年浙江温州瓯海科技产业发展集团有限公司及下属子公司招聘19人笔试历年参考题库附带答案详解
- 上海市长宁区2026年中考二模英语试卷(含答案无听力音频及原文)
- 2026 四年级下册 《小数加减混合运算》 课件
- 【高三下】2026年深圳市高三年级第二次调研考试语文试题含答案
- 山东青州第一中学2025-2026学年高三普通部二轮专题复习模拟考试(四)语文试题(含答案)
- 2026年高校辅导员实务工作试题及答案
- YY/T 0474-2025外科植入物聚丙交酯均聚物、共聚物和共混物体外降解试验
- 第9课 勤俭传家好 课件(内嵌视频) 2025-2026学年统编版道德与法治二年级下册
- 高新科技行业研发账服务协议
- 上交所社招笔试题
- 董事长司机考勤制度
- 人教版(2024)七年级下册数学全册教案(单元教学设计)
- 新年开学第一课:乘马年之风筑优良学风
- 中国老年人跌倒风险评估专家共识解读课件
评论
0/150
提交评论