(一)标识符
标识符是用来表示源程序中自定义对象名称的符号。自定义对象可以是常量、变量、数组、结构、句号和函数。
在C在51语言中,字母可以使用标识符(a~z,A~Z)、数字(0~9)和下划线_最多可支持32个字符。
C51标识符的定义不是随意的,应遵循简洁和知名的原则
?标识符的第一个字符必须是字母或下划线,而不是数字。由于一些编译系统的专用标识符从以下划线开始,用户在定义标识符时通常不会从以下划线开始。
?C51标识符区分大小写,如ch1”和“Ch表示两个不同的标识符。
?用户自定义的标识符不能与系统保留的关键字重复。
(二)关键词
关键字是C51编译器保留的一些特殊标识符具有特定的含义和用法。单片机C51程序语言继承ANSIC标准定义的32个关键字,如表3-1所示。
表3-1C51的关键字
同时C51结合单片机硬件的特点,扩展了19个关键词:
_at_idatasfr16alieninterruptsmallbdatalarge_task_codebitpdatausingreentrantxdatacompactsbitdatasfr
表3-2列出了KeiluVision2C51编译器支持的数据类型。
表3-2C51编译器支持的数据类型
1.char字符类型
char类型的长度是字节,通常用于定义字符数据的变量或常量。char字符类型分为无符号字符类型(unsignedchar)还有符号字符类型(signedchar),默认值为signedchar类型。
unsignedchar字节中的所有位置都用类型来表示值,可以表示0~255;signedchar字节最高位表示数据的符号,0表示正数,1表示负数(负数用补码表示),值范围为-128~127。
unsignedchar常用于处理ASCII或小于等于255的整形数字符。
正数补码与原码相同,负二进制数补码等于其绝对值取反后加1。
int存储双字节数据时,整形长度为两个字节。分为符号整形数signedint和无符号整形数unsignedint,默认值为signedint类型。
signedint值范围为-32768~32767,字节中最高位表示数据符号,0表示正数,1表示负数;unsignedint数值范围为0~65535。
long存储四字节数据的长度为四个字节。有符号长整形signedlong无符号长整形unsignedlong,默认值为signedlong类型。
signedint-2147483648~2147483647字节中最高位表示数据符号,0表示正数,1表示负数;unsignedlong数值范围为0~4294967295。
4.float浮点型
float十进制浮点型有7位有效数字,符合IEEE-754标准单精度浮点数据占用四个字节。浮点数结构复杂,单片机使用较少,这里不详细讨论。
指针数据本身就是一个变量,存储指向另一个数据的地址。根据处理器的不同,指针数据占用的内存单元也不同C其长度一般为51~3字节。
bit位标量是C一种扩展数据类型的51编译器,可以定义位标量,但不能定义位指针或位数组。其值为二进制位,非0即1。
定义格式:bit变量名=变量值。
7.sfr特殊功能寄存器
sfr占用内存单元的扩展数据类型为0x80~0xFF。
定义格式如下:sfr变量名=变量地址。
可访问51单片机内的所有特殊功能寄存器。例如,用“sfrP1=0x90”这一句定P1为P1端口在片内的寄存器。
8.sfr特殊功能寄存器1616
sfr16是占用两个内存单元的扩展数据类型,sfr16和sfr同样用于操作特殊功能寄存器,不同在于,这种类型的变量可以访问16作为特殊功能寄存器。
定义格式:sfr16变量名=变量地址。
这里的变量地址是16位中的低8位地址,地址范围为0x80~0xFF。通过sfr读取16个特殊功能寄存器时,先读低字节,再读高字节;写特殊功能寄存器时,先写高字节,再写低字节。
9.sbit可位寻址位
sbit是C使用它可以访问芯片内部的一种扩展数据类型RAM可寻址位或特殊功能寄存器中的可寻址位。
定义格式:
sbit变量名=位地址;sbit变量名=SFR地址^位序号;sbit变量名=sfr16变量^位序号。
因P1端口的寄存器可以找到位置,所以我们可以定义它P1_1为P1中的P1.我们也可以用1引脚P1.写下1的地址,以便在以后的程序语句中使用P1_1来对P1.读写操作引脚。
例如:
sbitP1_1=P1^1;
sbitP1_1=0x91
常量是程序运行过程中无法改变的量,如固定数据表、字符等。常量数据类型只有整形、浮点、字符、字符串和位标量。
1.整型常量
不同数据类型的整形常量表示方法不同,123、0、-89等十进制;06进制x开头如0x34,-0x3B等等;长整形在数字后面加字母L,如104L,034L,0xF340等。
2.浮点常量
浮点常量可分为十进制和指数表示。
十进制浮点常量由数字和小数点组成,整数或小数点为0,可以省略但必须有小数点,如0.888,3345.345,0.0等。
指数浮点常量表示为:[±]数字[.数字]e[±]数字
三、字符型常量
单引号中的字符是单引号中的字符,如‘a’,‘d’等。表示未显示的控制字符可在字符前添加反斜杠\形成专用转义字符,常用转义字符如表3-3所示。
4.字符串常量
字符串常量由双引号中的字符组成,如test”,“OK”等。引号中没有字符时,是空字符串。
C中的字符串常量作为字符类型数组处理,存储字符串时,系统会在字符串尾部添加\0转义字符作为字符串的结尾符。字符串常量字符串常量A和字符常量A不同的是,前者在存储时占用更多的字节空间。
常用转义字符表3-3
5.位标量
位标量是C51编译器是一种扩展数据类型,其值为二进制位,无0或1。
让我们来看一些常量定义的例子:
以上两句话的值都保存在程序存储器中,程序存储器在运行中不允许修改,因此如果在这两句话后面使用类似的值a=110,a编译时会出错。
变量是程序运行过程中可以不断变化的量,所有变量的定义都可以使用C51编译器支持数据类型。在程序中使用变量时,必须首先使用标识符作为变量名,并指出所使用的数据类型和存储模式,以便编译系统能够为变量分配相应的存储空间。
1.变量的定义和范围
变量格式的定义如下:
数据类型[存储类型]变量名表
除定义格式中,除数据类型和变量名表外,其他都是可选项。
(1)存储类型
不同存储类型的变量和不同位置定义的变量有不同的代码有效范围,即变量的作用域。在单片机程序中,可分为自动变量、全局变量、静态变量和寄存器变量。
①自动变量
关键词是自动变量auto通常在函数内部或复合语句中使用标识的变量类型。
函数或复合范围是函数或复合句的内部。在C在51中,当函数或复合语句内部定义自动变量时,关键字auto可以省略,即默认为自动变量。
自动变量在程序执行过程中动态分配存储空间。当程序执行到变量声明语句时,存储空间根据变量类型自动分配。当函数或复合句执行时,变量的存储空间将立即自动取消。此时,自动变量失效,该变量不能用于函数或复合句外。
②全局变量
关键词是全局变量extern如果标识的变量类型定义在所有函数的外部,即整个程序文件的前面,则该变量为全局变量。全局变量有时也被称为外部变量。
在编译程序时,静态分配适当的存储空间。该变量一旦分配空间,就不会在整个程序运行过程中消失。因此,整个程序文件中的任何函数都可以使用全局变量。
③静态变量
关键词是静态变量static从变量作用域的角度来看,静态变量与自动变量相似,作用域只定义变量的函数内部。若在函数外定义静态变量,则将具有整体作用域。
从内存占用的角度来看,静态变量类似于整体变量,它总是占据内存空间。
④寄存器变量
单片机的CPU少量的变量也可以保存在寄存器中,称为寄存器变量。以关键词为基础的寄存器变量register声明。
因为单片机对CPU寄存器的读写速度非常快,以寄存器变量的操作速度比其他类型的变量要快。寄存器变量常用于某个变量名的频繁使用,可以提高系统的运行速度。
由于单片机资源有限,只允许同时定义两个寄存器变量。如果超过两个,其他寄存器变量将自动作为非寄存器变量进行编译。
(2)存储类型
存储类型的描述是指定变量C在编译过程中准确定位硬件系统中使用的存储区域。表3-4中是KEILuVision2可识别的存储类型。
表3-4存储类型
在AT89C51芯片中RAM位于80位,只有低128位H到FFH52芯片中只有高128位,与特殊寄存器地址重叠。
如果存储类型被省略,系统将遵循编译模式small,compact或large指定变量存储区域的默认存储类型。
①small存储模式
small存储模式将函数参数和局部变量放在片中R
AM(默认变量类型为DATA,最大128字节)。此外,包括栈在内的所有对象都优先考虑RAM,当片内RAM满了,再到片外RAM放置。
②compact存储模式
compact将参数和局部变量放在存储模式中RAM(默认存储类型为PDATA,最大256字节);通过R0、R1间接寻址。
③large存储模式
large存储模式将参数和局部变量直接放入片外RAM(默认存储类型为XDATA,最大64KB);使用数据指针DPTR间接寻址,因此访问效率低。
(3)绝对定位变量
C关键扩展关键词_at_绝对定位变量,_at_变量定义中使用的格式为:
数据类型[存储区]变量名1_at_地址常数[,变量名2…]
①对data区域中的unsignedchar变量aa绝对定位:
unsignedchardataaa_at_0x30;
②对pdata区域中的unsignedint数组cc绝对定位:
unsignedintpdatacc[10]_at_0x34;
③对xdata区域中的unsignedchar变量printer_port绝对定位:
unsignedcharxdataprinter_port_at_0x7fff;
对变量绝对定位的几点说明:
①在定义不能初始化绝对地址变量,因此不能对code型常量绝对定位;
②绝对地址变量只能是全局变量,不能在函数中绝对定位变量;
③绝对地址变量多用于I/O一般情况下,端口不绝对定位变量;
④不能使用位变量_at_绝对定位。
2.变量的初始化和赋值
(1)变量的初始化
变量的初始化是指变量在被解释的同时赋予初始值。
2.变量的初始化和赋值
变量的初始化是指变量在被解释的同时赋予初始值。外部变量和静态全过程变量在程序开始时初始化,包括静态局部变量在内的局部变量在进入定义函数或复合语句时初始化。在没有明确初始化的情况下,所有全过程变量将自动清除,而局部变量和寄存器变量在赋值前的值不确定。
对于外部变量和静态变量,初始值必须是常数表达式,自动变量和寄存器变量可以是任何表达式,包括常数和上述变量和函数。
(2)变量赋值
变量赋值是给已解释的变量一个特定的值。
单变量赋值:
①整形变量和浮点变量
C当多个变量赋同一值时,语言允许连等。
②字符型变量
三种方法可以赋值字符变量。
所谓数组,有相同数据类型和共同名称的变量集。下标来访问数组中的每个特定元素。数组由连续存储地址组成,最低地址对应第一个数组元素,最高地址对应最后一个数组元素。数组可以是一维或多维的。
1.数组基本形式
(1)一维数组
一维数组的格式为:类型变量名[长度];
类型是指数据类型,即每个数组元素的数据类型,包括整数、浮点、字符、指针、结构和组合。
inta[10];
unsignedlonga[20];
char*s[5];
说明:数组以0作为第一个元素下标,所以当解释一个时inta[16]整形数组时,表示该数组有16个元素,a[0]~a[15],一个元素是整形变量。
一维数组表示大多数字符串。
大多数字符串用一维数组表示。数组元素的数量表示字符串的长度,数组名称表示字符串中第一个字符的地址,如句子charstr[8]在说明的数组中存储hello字符串后,str表示第一个字母h内存单元地址。str[0]存储字母h”的ASCII以此类推,str[4]存储在字母o”的ASCII码值,str[5]应存储字符串终止符\0’。
C大多数语言编译器对数组没有边界检查。
例如,用下面的句子解释两个数组
charstr1[5],str2[6];
当赋给str一个字符串ABCDEFG时间,只有ABCDE被赋予,E会自动赋予str应特别注意这一点。
多维数组的一般格式:
类型数组名[第n维长度][第n-1维长度]……[第一维长度];
数组m[3][2]共3*2=六个元素的顺序是:
m[0][0],m[0][1],m[1][0],m[1][1],m[2][0],m[2][1];
数组c[2][2][3]*2*3=12个元素的顺序是:
c[0][0][0],c[0][0][1],c[0][0][2],
c[0][1][0],c[0][1][1],c[0][1][2],
c[1][0][0],c[1][0][1],c[1][0][2],
c[1][1][0],c[1][1][1],c[1][1][2];
数组占用的内存空间(即字节数)计算为:
字节数=第1维长度*第2维长度*...*第n维长度*数组数据类型占用的字节数。
数组变量的初始化如下:
数组初始化有以下规则:
①数组的每一行初始化赋值都用{}和,分开,总的加上一对{},最后用;表示结束。
②多维数组的存储是根据最右维数变量变化最快的原则。
③多维数组存储是连续的,所以多维数组可以初始化。
④当数组初始化时,如果初值表中的数据比数组元素少,则用0填充不足的数组元素。
⑤指针变量数组不能规定维数,在初始化赋值时,数组维数从0开始连续赋值。
初始化将赋值三个字符指针,即:*f[0]='a',*f[1]='b',*f[2]='c'。
3.数组变量的赋值
例如:
编译时遇到上述程序chars[30]在此语句中,编译程序会在内存的某处留出连续30个字节的区域,并将第一个字节的地址给出s。当遇到strcpy在函数中,首先在目标文件的某个地方建立一个GoodNews!当遇到strcpy在函数中,首先在目标文件的某个地方建立一个GoodNews!\0字符串。其中“\0表示字符串终止,编译时自动添加终止符,然后将字符复制到s所指的内存区域。因此,在定义字符串数组时,其元素数应至少比字符串长1。
①不能使用字符串数组=直接赋值,即s=“GoodNews!是违法的。因此,应区分字符串数组和字符串指针的不同赋值方法。
②对于长字符串,TurboC2.允许使用以下方法:
(二)指针
指针定义的一般形式是:类型识别符*指针变量名;
C51支持一般指针(GenericPointer)以及存储器指针(Memory_SpecificPointer)。
一般指针的声明和使用与标准C相同,但也可以说明指针的存储类型。
(1)一般指针
一般指针的声明和使用与标准C相同,但也可以说明指针的存储类型。
以上的long、char指针指向的数据可以存储在任何存储器中。一般指针本身存储在三个字节中,分别存储存储类型、高偏移和低偏移。
(2)存储指针
基于存储器的指针指定了存储类型,例如:
存放此指针时,只需1或2个字节即可,因为只需存放偏移量。
2.指针变量的初始化
3.赋值指针变量
main()
int*i;
char*str;
*i=100;
str="Good";
*i表示i是指向整形数的指针,即*i是整形变量,i指向整形变量的地址。
*str表示str是字符型指针,即保留字符地址。初始化时,str没有特殊值,但在执行中str=“Good编译器首先在目标文件的某个地方保留一个存储空间的空间Good\0字符串,然后将字符串的第一个字母G地址赋予str,字符串结尾符\编译程序自动添加0。初始化时,str没有特殊值,但在执行中str=“Good编译器首先在目标文件的某个地方保留一个存储空间的空间Good\0字符串,然后将字符串的第一个字母G地址赋予str,字符串结尾符\编译程序自动添加0。
特别注意指针变量的使用。例如,两个指针在解释之前没有初始化,所以这两个指针是随机地址,在小存储模式下使用会有损坏机器的危险。正确的使用方法如下:
i=(int*)malloc(sizeof(int));
i=420;
str=(char*)malloc(20);
str="Good,Answer!";
函数(int*)malloc(sizeof(int))表示连续分配sizeof(int)=两个字节的整型数存储空间,并返回其第一个地址。同样(char*)malloc(20)表示连续分配20个字节的字符存储空间,并返回第一个地址(详细说明函数后)。动态内存分配函数malloc()内存空间分配后,这部分内存将用于指针变量。
若要使i指向三个整形数,则采用以下方法。
#include
i=(int*)malloc(3*sizeof(int));
*(i1)=4567;
*(i2)=234;
*i=1234表示将1234存储在i指向的地址中,但对于*(i1)=如果认为4567存储在i指向的下一个字节中是错误的。只要一些C语言编译器说明i是整形指针,(i1)等价于i1*sizeof(int)同样(i2)等价于i2*sizeof(int)。只要一些C语言编译器说明i是整形指针,(i1)等价于i1*sizeof(int)同样(i2)等价于i2*sizeof(int)。
(3)数组与指针的关系
数组与指针密切相关。数组名本身就是数组的指针。相反,指针也可以被视为数组。数组名和指针本质上是地址,但指针是变量,可以操作。而且数组名是常量,不能操作。
数组与指针的关系如下:
(pi)=&(s[i]),*(pi)=s[i];
因此,数组和指针可以通过上述表达式进行交换。两者之间的区别只是:数组s是程序自动分配所需的存储空间;指针p利用动态分配函数分配存储
存储空间或给它一个已分配的空间地址。
以上介绍了C语言中的基本数据类型。在实际的C语言程序设计中,仅仅这些基本类型的数据是不够的。有时需要将一批各种类型的数据放在一起,以引入结构类型的数据-结构和组合。
结构是一种结构类型的数据,它可以组合多种不同类型的数据变量,是一种数据集合。组成该集合体的变量称为结构成员,集合体使用单独的结构变量名。结构中的每个变量通常都有一定的相关性,如时间数据中的时间、分、秒、周、午、月、日等。结构是将一组相关数据变成一个整体进行处理,在程序中使用结构有利于处理一些复杂而内部的数据。
方法一:先定义结构类型,再定义结构变量名。
定义结构类型的一般形式如下:
结构元素表是结构中的每个成员(也称为结构域)。由于结构可以由不同类型的数据组成,因此应解释结构中的每个成员的类型。
例如,定义日期结构类型date格式如下:
在定义结构类型后,可以使用它来定义结构变量。一般格式为:
struct结构名结构变量名l,结构变量名2,…,结构变量名n;
structdated1,d2;
方法二:定义结构变量名,同时定义结构类型。
将方法一的两个步骤放在一起,一般格式如下:
{结构元素表}结构变量名1,结构变量名2,…,结构变量名n;
方法三:结构变量的直接定义。该方法可省略结构名称,又称无名结构,一般形式为:
strut
方法四:用typedef命名结构类型(此时结构名称不太重要)。
结构类型和结构变量是两个不同的概念。在定义结构类型时,只给出结构的组织形式,而不给出具体的组织成员。结构名称不占用任何存储空间,不能赋值、访问和计算结构名称。结构变量是结构中的特定成员。编译器将为特定的结构变量名分配确定的存储空间,因此可以赋值、访问和操作结构变量名。
将变量定义为基本类型与定义为结构类型的区别在于:前者只解释变量的类型,后者不仅解释变量为结构类型,而且指出变量所属结构类型的名称。
结构中的结构元素可以是另一种结构类型的变量,即可以形成结构嵌套。
结构类型mrec中间的结构元素time另一种结构类型clock结构变量形成结构结构,即结构嵌套,结构嵌套可以是多层次的,但这种嵌套不能包含自己,即结构不能定义自己。
结构中的结构元素可与结构外的其他变量同名。它们代表不同的对象,在使用中不会相互影响。
在定义结构变量时,也可以解释其存储类型extern、auto和static三种形式。
2.引用结构变量
定义结构变量后,应考虑引用问题(赋值、存取、操作)。引用结构变量是通过引用结构元素来实现的。引用结构元素的一般格式为:
结构变量名.结构元素
其中“.是存取结构元素的成员运算符。如d1.month表示结构变量d1中的成员month。如果一个结构变量中的结构元素是另一个结构变量.也就是说,当结构嵌套出现时,需要使用多个成员操作符逐级找到最低结构元素,只能访问最低结构元素,例如:m1.time.min。
结构变量中的每个元素都可以像普通变量一样赋值、访问和操作。
d1.year=2006;
sum=d1.dayd2.day;
d1.month;
m1.time.hour=0x22;
成员运算符的优先级最高。
程序中可以直接引用结构变量和结构元素的地址。
例:scanf(“%d”&d1.year);
结构变量地址通常用作传递结构地址的函数参数。
3.结构变量的初始值
当结构变量为外部全局变量或静态变量时,可以在定义结构类型时赋予其初始值,但不能赋予自动存储类型的动态局部结构变量初始值。
定义时不能赋予自动结构变量的初始值,只能在程序执行中使用赋值语句分别赋予各结构元素。结构变量的初始值必须小于等于结构变量中元素的数量。当初始值不够时,剩余的结构变量元素为0,如果初始值数超过元素数,则会导致编译错误。
4.结构数组
在实际使用中,结构变量通常不止一个,通常将多个相同的结构组成一个结构数组,结构数组的定义方法与结构变量完全一致。
5.结构指针
(1)结构指针概念
指向结构类型变量的指针称为结构类型指针,指针变量的值也是指向结构变量的起始地址。结构指针也用于指向结构数组或结构数组中的元素。
定义结构指针的一般形式如下:
struct结构类型标识符*结构指针标识符
结构指针标识符是定义的结构指针变量的名称,结构类型标识是指针指向的结构变量的具体类型名称。
例:structmepoint*mp;
(2)用结构指针引用结构元素
结构元素引用结构指针的一般形式为:
结构指针→结构元素
例:mp→pressure等同于(*mp).pressure
6.结构和函数
(1)结构作为函数的参数
一般来说,结构可作为函数的参敏,也可作为函数的返回值。当结构被用作函数的参数时,其用法与普通变量相同,其参数传递属于值传递。当结构被用作函数的参数时,其用法与普通变量相同,其参数传递属于值传递。
在调用函数时,程序将整个结构变量作为参数传递给被调用函数。该系统将存储空间分配为形式参数的结构变量,并从相应的实际参数中获得每个元素的值。函数对形参中各结构无素值的修改不会对相应的实参结构变量产生任何影响。
(2)作为函数参数的结构指针
当结构较大时,如果结构作为函数的参数,由于参数传输采用值传输方式,需要较大的存储空间(堆叠)来堆叠和离开所有结构元素,特别是当函数参数是结构数组时,影响更大,但也会影响程序的执行速度。事实上,结构指针可以用作函数的参数。此时,参数的传输是根据地址传输进行的。由于地址传输方式,只需一个地址值,与前者相比,它不仅可以节省存储空间,而且可以加快程序的执行。缺点是调用函数时结构指针的任何变化都会影响原来的结构变量。
(二)联合
联合也是C语言中的一种结构数据结构。多种不同类型的数据元素可以包含在一个组合中。在同一地址开始的内存单元中放置各种类型的变量,实现多层数据覆盖,一方面有效提高了内存的利用率,另一方面也促进了数据类型之间的转换。
1.联合定义
定义联合类型变量的一般形式:
union联合类型名
{成员表列}变量表列;
类型定义也可以与变量定义分开。先定义一个uniondata类型,再将a、b、c定义为uniondata类型变量。
联合变量也可以直接定义。
由此可见,联合类型的定义方法与结构类型非常相似,只是关键字struct改成了union。但它们在内存分配上有本质的区别。结构变量占用的内存长度是各元素占用的内存长度的总和;联合变量占用的时存长度是其中最长的元素。联合变量中的元素分时占用相同的存储空间。
类似于结构变量,联合变量的引用也是通过引用联合元素来实现的,引用联合元素的一般格式是:
联合变量名.联合元素
联合变量名->联台元素
a.i///引用联合变量afloat型元素
a.j///引用联合变量along型元素
b.k///引用联合变量bint型元素
c.m///引用联合变量cchar型元素
在引用联合元素时,注意联合变量用法的一致性。由于联合类型中定义的不同类型的元素可以分时赋予变量,读取的变量值是最近添加的某一元素的值,因此在表达式中处理时,必须注意其类型应与表达式要求的类型一致,否则会导致程序运行错误。
联合变量不能整体引用。例如,以下写法是错误的:
printf(“%f”,a);
因为变量a可能是float、long、int和char如果引用时只写联合变量名,三种类型分别占用不同长度的内存区域a,系统很难确定应该输出哪个联合元素值。
printf(“%f”,a.i);
联合数据占用的内存空间只能在某一时刻存储一种元素。
毕业证样本网创作《c语言程序设计(单片机C语言程序设计基础知识全解析)》发布不易,请尊重! 转转请注明出处:https://www.czyyhgd.com/735369.html