1、 4.1 顺序结构顺序结构 4.2 选择结构选择结构 4.3 循环结构循环结构 4.4 C51 数组数组 4.5 函数函数 4.6 程序设计程序设计返回4.1 顺顺 序序 结结 构构顺序结构是一种最基本、最简单的编程结构。在这种结构中,程序由顺序结构是一种最基本、最简单的编程结构。在这种结构中,程序由低地址向高地址顺序执行指令代码。如低地址向高地址顺序执行指令代码。如图图4.1 所示,程序先执行所示,程序先执行A 操操作,再执行作,再执行B 操作,两者是顺序执行的关系。操作,两者是顺序执行的关系。例例4.1 要求把内部要求把内部RAM 30H 中的一个压缩中的一个压缩BCD 码(如码(如97H
2、),转换),转换为十六进制数,并把该数存放入内部为十六进制数,并把该数存放入内部RAM 31H,编程实现之。,编程实现之。#include#include void main()unsigned char data a20;下一页返回4.1 顺顺 序序 结结 构构DBYTE0 x30=0 x97;a0=0 x97;a2=a0;a1=a14;a1=a1*10;a2=a2&0 x0F;a1=a1+a2;DBYTE0 x31=a1;while(1);上一页返回4.2 选选 择择 结结 构构 4.2.1 if 语句的三种基本形式语句的三种基本形式C51 语言的语言的if 语句有三种基本形式。语句有三种
3、基本形式。1.第一种形式(基本形式)第一种形式(基本形式)if(表达式表达式)语句语句其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该语句,其过程如语句,其过程如图图4.2 所示。所示。例例4.4 输入两个整数,输出其中的大数。请编程实现此功能。输入两个整数,输出其中的大数。请编程实现此功能。#include void main()下一页返回4.2 选选 择择 结结 构构int a,b,max;printf(n input two numbers:);scanf(%d%d,&a,&b);max=a;if(maxb)max=
4、b;printf(max=%d,max);上一页 下一页返回4.2 选选 择择 结结 构构2.第二种形式第二种形式if(表达式表达式)语句语句1;else语句语句2;其语义是:如果表达式的值为真,则执行语句其语义是:如果表达式的值为真,则执行语句A,否则执行语句,否则执行语句B。其过程如其过程如图图4.3 所示。所示。上一页 下一页返回4.2 选选 择择 结结 构构3.第三种形式(第三种形式(if-else-if 形式)形式)前两种形式的前两种形式的if 语句一般都用于两个分支的情况。当有多个分支选择语句一般都用于两个分支的情况。当有多个分支选择时,可采用时,可采用if-else-if语句,其
5、一般形式为:语句,其一般形式为:if(表达式表达式1)语句语句1;else if(表达式表达式2)语句语句2;else if(表达式表达式3)语句语句3;上一页 下一页返回4.2 选选 择择 结结 构构else if(表达式表达式m)语句语句m;else语句语句n;其语义是:依次判断表达式的值,当出现某个值为真时,则执行其到其语义是:依次判断表达式的值,当出现某个值为真时,则执行其到整个整个if 语句之外继续执行程序。如果所有的表达式均为假,则执行语语句之外继续执行程序。如果所有的表达式均为假,则执行语句句n。然后继续执行后续程序。使用。然后继续执行后续程序。使用if 语句应注意以下问题:语句
6、应注意以下问题:(1)在三种形式的在三种形式的if 语句中,在语句中,在if 关键字之后均为表达式。该表达关键字之后均为表达式。该表达式通常是逻辑表达式或关系表达式,但也可以是其他表达式,如赋值式通常是逻辑表达式或关系表达式,但也可以是其他表达式,如赋值表达式等,甚至也可以是一个变量。表达式等,甚至也可以是一个变量。上一页 下一页返回4.2 选选 择择 结结 构构例如:例如:“if(a=5)语句;)语句;”“”“if(b)语句;)语句;”都是允许的。只要表都是允许的。只要表达式的值为非达式的值为非0,即为,即为“真真”。如在。如在“if(a=5);”中,表达式中,表达式的值永远为非的值永远为非
7、0,所以其后的语句总是要执行的,当然这种情况在程,所以其后的语句总是要执行的,当然这种情况在程序中不一定会出现,但在语法上是合法的。序中不一定会出现,但在语法上是合法的。(2)在在if 语句中,条件判断表达式必须用括号括起来,在语句之后语句中,条件判断表达式必须用括号括起来,在语句之后必须加分号。必须加分号。(3)在在if 语句的三种形式中,所有的语句应为单个语句,如果要想语句的三种形式中,所有的语句应为单个语句,如果要想在满足条件时执行一组(多个)语句,则必须把这一组语句用在满足条件时执行一组(多个)语句,则必须把这一组语句用“”括起来组成一个复合语句。但要注意的是在括起来组成一个复合语句。
8、但要注意的是在“”之后不能再加分号。之后不能再加分号。上一页 下一页返回4.2 选选 择择 结结 构构(4)if 语句的嵌套。语句的嵌套。当当if 语句中的执行语句又是语句中的执行语句又是if 语句时,则构成了语句时,则构成了if 语句嵌套的情形。语句嵌套的情形。其一般形式可表示如下:其一般形式可表示如下:if(表达式表达式)if 语句语句;或者为:或者为:if(表达式表达式)if 语句语句;elseif 语句语句;上一页 下一页返回4.2 选选 择择 结结 构构在嵌套内的在嵌套内的if 语句可能又是语句可能又是if-else 型的,这将会出现多个型的,这将会出现多个if 和多个和多个else
9、 重叠的情况,这时要特别注意重叠的情况,这时要特别注意if 和和else 的配对问题。的配对问题。4.2.2 switch-case 语句语句C51 语言还提供了另一种用于多分支选择的语言还提供了另一种用于多分支选择的switch 语句,其一般形语句,其一般形式为:式为:switch(表达式表达式)case 常量表达式常量表达式1:语句语句1;上一页 下一页返回4.2 选选 择择 结结 构构case 常量表达式常量表达式2:语句语句2;case 常量表达式常量表达式n:语句语句n;default:语句语句n+1;其语义是:计算表达式的值,并逐个与其后的常量表达式值相比较,其语义是:计算表达式的
10、值,并逐个与其后的常量表达式值相比较,当表达式的值与某个常量表达式的值相等时,即执行其后的语句,然当表达式的值与某个常量表达式的值相等时,即执行其后的语句,然后不再进行判断,继续执行后面所有后不再进行判断,继续执行后面所有case后的语句。如果表达式的后的语句。如果表达式的值与所有值与所有case 后的常量表达式均不相同时,则执行后的常量表达式均不相同时,则执行default 后的语句。后的语句。其执行流程图如其执行流程图如图图4.4 所示。所示。上一页 下一页返回4.2 选选 择择 结结 构构在使用在使用switch 语句时还应注意以下几点:语句时还应注意以下几点:(1)在在case 后的各
11、常量表达式的值不能相同,否则会出现错误。后的各常量表达式的值不能相同,否则会出现错误。(2)在在case 后,允许有多个语句,可以不用后,允许有多个语句,可以不用“”括起来。括起来。(3)各各case 和和default 子句的先后顺序可以变动,而不会影响程序子句的先后顺序可以变动,而不会影响程序执行结果。执行结果。(4)default 子句可以省略不用。子句可以省略不用。上一页返回下一页4.2 选选 择择 结结 构构 4.2.3 break语句语句C51语言还提供了一种语言还提供了一种break语句,专用于跳出语句,专用于跳出switch语句。语句。Break语句只有关键字语句只有关键字br
12、eak,没有参数。,没有参数。上一页返回4.3 循循 环环 结结 构构程序设计中,常常要求某一段程序重复执行多次,这时可采用循环结程序设计中,常常要求某一段程序重复执行多次,这时可采用循环结构程序。这种结构可大大简化程序,但程序执行的时间并不会减少。构程序。这种结构可大大简化程序,但程序执行的时间并不会减少。图图4.5 是典型的当型循环结构,控制语句在循环体之前,所以在结束是典型的当型循环结构,控制语句在循环体之前,所以在结束条件已具备的情况下,循环体程序可以一次也不执行,条件已具备的情况下,循环体程序可以一次也不执行,C51 提供了提供了while 和和for 语句实现这种循环结构。语句实现
13、这种循环结构。图图4.6 中其控制部分在循环体之后,因此,即使在执行循环体程序之中其控制部分在循环体之后,因此,即使在执行循环体程序之前结束条件已经具备,循环体程序至少还要执行一次,因此称为直到前结束条件已经具备,循环体程序至少还要执行一次,因此称为直到型循环结构,型循环结构,C51 提供了提供了do-while 语句实现这种循环结构。语句实现这种循环结构。下一页返回4.3 循循 环环 结结 构构循环程序一般包括以下循环程序一般包括以下4 个部分:个部分:(1)初始化:置循环初值,即设置循环开始的状态,比如设置地址初始化:置循环初值,即设置循环开始的状态,比如设置地址指针、设定工作寄存器、设定
14、循环次数等。指针、设定工作寄存器、设定循环次数等。(2)循环体:这是要重复执行的程序段,是循环结构的基本部分。循环体:这是要重复执行的程序段,是循环结构的基本部分。(3)循环控制:循环控制包括修改指针、修改控制变量和判断循环循环控制:循环控制包括修改指针、修改控制变量和判断循环是否结束还是继续,修改指针和变量是为下一次循环判断做准备,当是否结束还是继续,修改指针和变量是为下一次循环判断做准备,当符合结束条件时,结束循环;否则,继续循环。符合结束条件时,结束循环;否则,继续循环。(4)结束:存放结果或做其他处理。结束:存放结果或做其他处理。在循环程序中,有两种常用的控制循环次数的方法:一种是循环
15、次数在循环程序中,有两种常用的控制循环次数的方法:一种是循环次数已知,这时把循环次数作为循环计算器的初值,当计数器的值加满或已知,这时把循环次数作为循环计算器的初值,当计数器的值加满或减为减为0 时,即结束循环;否则,继续循环。时,即结束循环;否则,继续循环。上一页 下一页返回4.3 循循 环环 结结 构构另一种是循环次数未知,这时可根据给定的问题条件来判断是否继续。另一种是循环次数未知,这时可根据给定的问题条件来判断是否继续。一、一、while 语句语句while 语句的一般形式为:语句的一般形式为:while(表达式表达式)语句语句;其中表达式是循环条件,语句为循环体。其中表达式是循环条件
16、,语句为循环体。while 语句的语义是:计算表达式的值,当值为真(非语句的语义是:计算表达式的值,当值为真(非0)时,执行)时,执行循环体语句。循环体语句。上一页 下一页返回4.3 循循 环环 结结 构构例例4.9 统计从键盘输入一行字符的个数。请编程实现此功能。统计从键盘输入一行字符的个数。请编程实现此功能。#include void main()int n=0;printf(input a string:n);while(getchar()!=n)n+;printf(%d,n);上一页 下一页返回4.3 循循 环环 结结 构构(1)while 语句中的表达式一般是关系表达式或逻辑表达式,
17、只要语句中的表达式一般是关系表达式或逻辑表达式,只要表达式的值为真(非表达式的值为真(非0)即可继续循环。即可继续循环。(2)循环体如果包括有一个以上的语句,则必须用循环体如果包括有一个以上的语句,则必须用“”括起来,括起来,组成复合语句。组成复合语句。(3)应注意循环条件的选择以避免死循环。应注意循环条件的选择以避免死循环。二、二、do-while 语句语句do-while 语句的一般形式为:语句的一般形式为:do语句语句;上一页 下一页返回4.3 循循 环环 结结 构构while(表达式表达式);其中语句是循环体,表达式是循环条件。其中语句是循环体,表达式是循环条件。do-while 语句
18、的语义是:先执行循环体语句一次,再判别表达式的语句的语义是:先执行循环体语句一次,再判别表达式的值,若为真(非值,若为真(非0)则)则继续循环,否则终止循环。继续循环,否则终止循环。do-while 语句和语句和while 语句的区别在于语句的区别在于do-while 是先执行后判断,是先执行后判断,因此因此do-while 至少要至少要执行一次循环体。而执行一次循环体。而while 是先判断后执行,如果条件不满足,则循是先判断后执行,如果条件不满足,则循环体语句一次也不执行。环体语句一次也不执行。while 语句和语句和do-while 语句一般都可以相互改写。语句一般都可以相互改写。上一页
19、 下一页返回4.3 循循 环环 结结 构构三、三、for 语句语句for 语句的一般格式为:语句的一般格式为:for(变量赋初值变量赋初值;循环继续条件循环继续条件;循环变量增值循环变量增值)循环体语句组循环体语句组;执行过程如执行过程如图图4.7 所示。所示。(1)求解求解“变量赋初值变量赋初值”表达式表达式1。(2)求解求解“循环继续条件循环继续条件”表达式表达式2。如果其值非。如果其值非0,执行步骤,执行步骤(3);否则,转至步骤();否则,转至步骤(4)。)。(3)执行循环体语句组,并求解执行循环体语句组,并求解“循环变量增值循环变量增值”表达式表达式3,然后,然后转向步骤(转向步骤(
20、2)。)。上一页 下一页返回4.3 循循 环环 结结 构构(4)执行执行for 语句的下一条语句。语句的下一条语句。对对“变量赋初值变量赋初值”“”“循环继续条件循环继续条件”和和“循环变量增值循环变量增值”部分均可缺部分均可缺省,甚至全部缺省,但其间的分号不能省略。省,甚至全部缺省,但其间的分号不能省略。当循环体语句组仅由一条语句构成时,可以不使用复合语句形式。当循环体语句组仅由一条语句构成时,可以不使用复合语句形式。“循环变量赋初值循环变量赋初值”表达式表达式1,既可以是给循环变量赋初值的赋值表,既可以是给循环变量赋初值的赋值表达式,也可以是与此无关的其他表达式(如逗号表达式)。达式,也可
21、以是与此无关的其他表达式(如逗号表达式)。“循环继续条件循环继续条件”部分是一个逻辑量,除一般的关系(或逻辑)表达部分是一个逻辑量,除一般的关系(或逻辑)表达式外,也允许是数值(或字符)表达式。式外,也允许是数值(或字符)表达式。for 语句中的各表达式都可省略,但分号间隔符不能少。语句中的各表达式都可省略,但分号间隔符不能少。上一页返回4.4 C51 数数 组组数组是一组具有固定数目和相同类型成分分量的有序集合。数组是一组具有固定数目和相同类型成分分量的有序集合。1.一维数组一维数组定义:类型说明符定义:类型说明符 数组名整型表达式数组名整型表达式2.二维数组二维数组定义:类型说明符定义:类
22、型说明符 数组名常量表达式常量表达式数组名常量表达式常量表达式3.字符数组字符数组定义方法同上。定义方法同上。字符数组中字符数组中 括起来的一串字符,称为字符串常量。括起来的一串字符,称为字符串常量。C 语言编译器语言编译器会自动地在字符末尾加上结束符会自动地在字符末尾加上结束符o(NULL);用);用 括起来的字符为括起来的字符为字符的字符的ASCII 码值而不是字符串。比如:码值而不是字符串。比如:a 表示表示a 的的ASCII 码值码值97,而而a 表示一个字符串,它由两个字符组成,即表示一个字符串,它由两个字符组成,即a 和和o。下一页返回4.4 C51 数数 组组一个字符串可以用一个
23、一维数组来装入,但数组的元素数目一定要比一个字符串可以用一个一维数组来装入,但数组的元素数目一定要比字符多一个,以便字符多一个,以便C 编译器自动在其后面加入结束符编译器自动在其后面加入结束符 o。二维字符数组中,第一个下标是字符串的个数,第二个下标定义每个二维字符数组中,第一个下标是字符串的个数,第二个下标定义每个字符串的长度,该长度应当比这批字符串中最长的串多一个字符,用字符串的长度,该长度应当比这批字符串中最长的串多一个字符,用于装入字符串的结束符于装入字符串的结束符 o。上一页返回4.5 函函 数数C 语言程序的一般组成结构:语言程序的一般组成结构:下一页返回4.5 函函 数数普通函数
24、之间可以互相调用,但普通函数不能调用主函数。普通函数之间可以互相调用,但普通函数不能调用主函数。一个一个C 程序的指向从程序的指向从main()函数开始,调用其他函数后返回到主函函数开始,调用其他函数后返回到主函数数main()中,最后在主函数中,最后在主函数main()中结束整个中结束整个C 程序的运行。程序的运行。1.函数的分类函数的分类C 语言函数分为主函数语言函数分为主函数main()和普通函数两种。普通函数从不同角和普通函数两种。普通函数从不同角度又可分为:度又可分为:从用户使用的角度划分:标准库函数、用户自定义函数;从用户使用的角度划分:标准库函数、用户自定义函数;从函数定义的形式
25、上划分:无参数函数、有参数函数、空函数。从函数定义的形式上划分:无参数函数、有参数函数、空函数。上一页 下一页返回4.5 函函 数数2.函数的定义函数的定义(1)无参数函数的定义。无参数函数的定义。返回值类型标识符返回值类型标识符 函数名函数名()函数体语句函数体语句无参数函数一般不带返回值,因此函数返回值类型标识无参数函数一般不带返回值,因此函数返回值类型标识符可以省略。符可以省略。(2)有参数函数的定义。有参数函数的定义。返回值类型标识符返回值类型标识符 函数名函数名(形式参数列表形式参数列表)函数体语句函数体语句上一页 下一页返回4.5 函函 数数(3)空函数的定义。空函数的定义。返回值
26、类型说明符返回值类型说明符 函数名函数名()3.函数的参数和函数值函数的参数和函数值函数调用时,其参数传递由主调函数的实际参数与被调函数的形式参函数调用时,其参数传递由主调函数的实际参数与被调函数的形式参数之间进行数据传递,即实际参数传递给形式参数,被调函数的最后数之间进行数据传递,即实际参数传递给形式参数,被调函数的最后结果由被调函数的结果由被调函数的return 语句返回给调用函数。语句返回给调用函数。(1)形式参数和实际参数。形式参数和实际参数。形式参数:在定义函数时,函数名后面括号中的变量名称为形式参数:在定义函数时,函数名后面括号中的变量名称为“形参形参”;实际参数:在函数调用时,主
27、调函数名后面括号中的表达式称为实际参数:在函数调用时,主调函数名后面括号中的表达式称为“实实参参”。上一页 下一页返回4.5 函函 数数在在C 语言的函数调用中,实际参数与形式参数之间的数据传递是单向语言的函数调用中,实际参数与形式参数之间的数据传递是单向进行的。只能由实参传递给形参,而不能由形参传递给实参。实参与进行的。只能由实参传递给形参,而不能由形参传递给实参。实参与形参的类型必须一致,否则会发生类型不匹配的错误。形参的类型必须一致,否则会发生类型不匹配的错误。(2)函数的返回值。函数的返回值。一般来说,函数的返回值只有一个值,若函数的返回值是多个值时,一般来说,函数的返回值只有一个值,
28、若函数的返回值是多个值时,采用数组形式,并且数组必须为全局变量。采用数组形式,并且数组必须为全局变量。4.函数的调用函数的调用(1)函数调用的一般形式:函数调用的一般形式:函数名函数名(实参列表实参列表);(2)函数调用的方式。函数调用的方式。上一页 下一页返回4.5 函函 数数函数调用语句;函数调用语句;函数结果作为表达式的一个运算对象;函数结果作为表达式的一个运算对象;函数参数:被调函数作为另一个函数的实参。函数参数:被调函数作为另一个函数的实参。(3)对被调函数的说明。对被调函数的说明。在一个函数中调用另一个函数必须具有以下条件:在一个函数中调用另一个函数必须具有以下条件:被调函数必须是
29、已经存在的函数(库函数或用户自定义函数);被调函数必须是已经存在的函数(库函数或用户自定义函数);如果程序中使用了库函数,或不在同一文件中的另外的自定义函数,如果程序中使用了库函数,或不在同一文件中的另外的自定义函数,则应该在程序的开则应该在程序的开头处使用头处使用#include 包含语句,将所用的函数信息包括到程序中来;包含语句,将所用的函数信息包括到程序中来;上一页 下一页返回4.5 函函 数数如果程序中使用自定义函数,且该函数与调用它的函数同在一个文件如果程序中使用自定义函数,且该函数与调用它的函数同在一个文件中,则应根据主调函数与被调函数在文件中的位置,决定是否对被调中,则应根据主调
30、函数与被调函数在文件中的位置,决定是否对被调函数做出说明:函数做出说明:如被调函数出现在主调函数之后,一般应在主调函数中在对被调如被调函数出现在主调函数之后,一般应在主调函数中在对被调函数调用之前对被调函数的返回值类型做出说明,其一般形式为:函数调用之前对被调函数的返回值类型做出说明,其一般形式为:返回值类型说明符返回值类型说明符 被调函数的函数名被调函数的函数名();如被调函数的定义出现在主调函数之前,可以不对被调函数加以如被调函数的定义出现在主调函数之前,可以不对被调函数加以说明。说明。如在所有函数定义之前,在文件开头处,在函数的外部已经说明了函如在所有函数定义之前,在文件开头处,在函数的
31、外部已经说明了函数的类型,则在主调函数中不必对所调函数再做返回值类型说明。数的类型,则在主调函数中不必对所调函数再做返回值类型说明。上一页 下一页返回4.5 函函 数数5.函数的嵌套函数的嵌套在在C 语言中,在调用一个函数的过程中,允许调用另一个函数。语言中,在调用一个函数的过程中,允许调用另一个函数。6.函数的递归调用函数的递归调用在调用一个函数的过程中,又直接或间接地调用该函数本身,这种情在调用一个函数的过程中,又直接或间接地调用该函数本身,这种情况称为函数的递归调用。况称为函数的递归调用。7.用函数指针变量调用函数用函数指针变量调用函数指向函数的指针变量的一般定义形式为:指向函数的指针变
32、量的一般定义形式为:函数值返回类型函数值返回类型(*指针变量名指针变量名)(函数形参表函数形参表)在给函数指针变量赋值时,只需给出函数名而不必给出参数,如在给函数指针变量赋值时,只需给出函数名而不必给出参数,如p=factorial。上一页 下一页返回4.5 函函 数数用函数指针变量调用函数时,只需将(用函数指针变量调用函数时,只需将(*p)代替函数名即可()代替函数名即可(p 为指为指针变量),在(针变量),在(*p)之后的括号中可根据需要写上实参。)之后的括号中可根据需要写上实参。对指向函数的指针变量进行诸如对指向函数的指针变量进行诸如p+n、p+、p 的运算是没有的运算是没有意义的。意义
33、的。8.数组、指针作为函数的参数数组、指针作为函数的参数当用数组名作函数的参数时,应该在调用函数和被调用函数中分别定当用数组名作函数的参数时,应该在调用函数和被调用函数中分别定义数组;义数组;实参数组与形参数组的类型应一致,否则将导致结果出错;实参数组与形参数组的类型应一致,否则将导致结果出错;实参数组与形参数组的大小可以一致,也可以不一致。实参数组与形参数组的大小可以一致,也可以不一致。上一页返回4.6 程程 序序 设设 计计一、程序的组成一、程序的组成程序应包括数据说明(由数据定义部分来实现)和数据操作(由语句程序应包括数据说明(由数据定义部分来实现)和数据操作(由语句来实现)。数据说明主
34、要定义数据结构(由数据类型表示)和数据的来实现)。数据说明主要定义数据结构(由数据类型表示)和数据的初值,数据操作的任务是对已提供的数据进行加工。初值,数据操作的任务是对已提供的数据进行加工。函数是函数是C 语言最基本的组成单位。语言最基本的组成单位。二、常用术语二、常用术语1.文件文件计算机中数据或程序都是以文件来存储的。文件是计算机的基本存储计算机中数据或程序都是以文件来存储的。文件是计算机的基本存储单位。计算机中用户可见的是各种各样的文件。单位。计算机中用户可见的是各种各样的文件。下一页返回4.6 程程 序序 设设 计计2.源程序文件源程序文件一个一个C 源程序文件是由一个或多个函数组成
35、的,它完成特定的功能。源程序文件是由一个或多个函数组成的,它完成特定的功能。3.目标文件目标文件目标文件包含所要开发使用的单片机的机器代码。目标指的是所要用目标文件包含所要开发使用的单片机的机器代码。目标指的是所要用的单片机;目标文件即目标程序文件,是单片机可执行的程序文件。的单片机;目标文件即目标程序文件,是单片机可执行的程序文件。4.汇编器汇编器/编译器编译器汇编器是针对汇编语言程序的;编译器是针对高级语言(如汇编器是针对汇编语言程序的;编译器是针对高级语言(如C 语言)语言)程序的。它们的作用是把源程序翻译成单片机可执行的目标代码产生程序的。它们的作用是把源程序翻译成单片机可执行的目标代
36、码产生一个目标文件。一个源程序文件是一个汇编一个目标文件。一个源程序文件是一个汇编/编译的单位。对编译的单位。对Keil C 工具软件,其汇编工具软件,其汇编/编译过程如编译过程如图图4.9 所示。所示。上一页 下一页返回4.6 程程 序序 设设 计计因因C 程序可由多个源文件组成,对每个源程序的编译只能得到相对地程序可由多个源文件组成,对每个源程序的编译只能得到相对地址,这需要最后重新进行统一的地址分配(定位)。列表文件是汇编址,这需要最后重新进行统一的地址分配(定位)。列表文件是汇编器或编译器生成的包含源程序、目标代码和错误信息等的可打印文件。器或编译器生成的包含源程序、目标代码和错误信息
37、等的可打印文件。5.段段段和程序存储器或数据存储器有关,有程序段和数据段。段可以是重段和程序存储器或数据存储器有关,有程序段和数据段。段可以是重定位的,有一个段名、类型及其属性。定位的,有一个段名、类型及其属性。6.模块模块模块是包含一个或多个段的文件。它由编程者命名。模块的定义决定模块是包含一个或多个段的文件。它由编程者命名。模块的定义决定局部符号的作用域。通常模块为显示、计算或用户接口相关的函数或局部符号的作用域。通常模块为显示、计算或用户接口相关的函数或子程序。子程序。上一页 下一页返回4.6 程程 序序 设设 计计7.库库库是包含一个或多个模块的文件。这些模块通常是由编译或汇编得到库是
38、包含一个或多个模块的文件。这些模块通常是由编译或汇编得到的可重定位的目标模块,在连接时和其他模块组合,连接器从库中仅的可重定位的目标模块,在连接时和其他模块组合,连接器从库中仅仅选择与其他模块相关的模块,即由其他模块调用的模块。仅选择与其他模块相关的模块,即由其他模块调用的模块。8.连接器连接器/定位器定位器连接是把各模块中所有具有相同段名及类型名的段连接起来生成一个连接是把各模块中所有具有相同段名及类型名的段连接起来生成一个完整程序的过程。连接由连接器完成。连接器识别所有的公共符号完整程序的过程。连接由连接器完成。连接器识别所有的公共符号(变量、函数和标号名)。一旦所有的外部(变量、函数和标
39、号名)。一旦所有的外部RAM 数据收集起来,而且没有和其他模块的地址重叠,定位器就可数据收集起来,而且没有和其他模块的地址重叠,定位器就可以决定绝对地址。定位器是分配地址给每个段的工具,在连接时把模以决定绝对地址。定位器是分配地址给每个段的工具,在连接时把模块的同名段放入一整段,定位时重新填入段的绝对地址。块的同名段放入一整段,定位时重新填入段的绝对地址。上一页 下一页返回4.6 程程 序序 设设 计计9.应用程序应用程序应用程序是整个开发过程的目的。它是单一的绝对目标文件,它是把应用程序是整个开发过程的目的。它是单一的绝对目标文件,它是把全部输入模块的所有绝对的及可重新定位的段连接起来,最后
40、形成的全部输入模块的所有绝对的及可重新定位的段连接起来,最后形成的单一的绝对模块。单一的绝对模块。C51 连接器连接器/定位器如定位器如图图4.10 所示。所示。三、文件命名常规三、文件命名常规程序文件有几个常用的扩展名,典型的源文件程序文件有几个常用的扩展名,典型的源文件是:是:.ASM,.A51,.P51,.C51 或或.C;.ASM或或.A51 是汇编语言源文是汇编语言源文件;件;.C51 或或.C 是是C 语言源文件。包含汇编语言源文件。包含汇编/编译的程序和错误的列表编译的程序和错误的列表文件是文件是.LST。可重定位的目标模块为。可重定位的目标模块为.OBJ 文件。而最后的绝对目标
41、文件。而最后的绝对目标文件用同名而无扩展名的文件表示。文件用同名而无扩展名的文件表示。上一页 下一页返回4.6 程程 序序 设设 计计若转换成若转换成Intel 的目标文件格式是的目标文件格式是.HEX;库文件是;库文件是.LIB;连接定位后;连接定位后的映像文件是的映像文件是.M51或或.MAP。连接器。连接器/定位器使用的文件是定位器使用的文件是.LNK。在。在编译时加入到源文件中的头文件是编译时加入到源文件中的头文件是.H。.HEX 是结果输出的目标文件格式,至少是结果输出的目标文件格式,至少Intel 和和Keil 是采用是采用“Intel HEX 格式格式”。HEX 格式不难辨认,它
42、的格式是文件中的所有字节是格式不难辨认,它的格式是文件中的所有字节是可打印的可打印的ASCII 字符。其他更紧凑格式字符。其他更紧凑格式“BIN”以单一字节表示每个以单一字节表示每个程序代码字节,这样文件中有许多非打印的程序代码字节,这样文件中有许多非打印的ASCII 字符代码。字符代码。HEX 文件中的冒号(:)标示一个新记录,接着的两个字符是以实际数据文件中的冒号(:)标示一个新记录,接着的两个字符是以实际数据字节数表示的记录块的长度,典型的字节数表示的记录块的长度,典型的10 代表一个代表一个16 个数据字节的块。个数据字节的块。再下面的四个字符是十六进制数,用于表示块中数据的起始地址。
43、再再下面的四个字符是十六进制数,用于表示块中数据的起始地址。再下面的两个字符是块的类型码下面的两个字符是块的类型码00 表示可重定位数据;表示可重定位数据;上一页 下一页返回4.6 程程 序序 设设 计计01 是文件的结束标志。接下去是实际数据,每个十六进制的数字对是文件的结束标志。接下去是实际数据,每个十六进制的数字对表示一个字节,表示一个字节,16 字节数据以字节数据以32 个字符表示。最后两位数据表示校个字符表示。最后两位数据表示校验和,很容易与数据混淆。当所有的两字符十六进制值与校验和加起验和,很容易与数据混淆。当所有的两字符十六进制值与校验和加起来以来以256 取模时,整个结果为取模
44、时,整个结果为0。四、模块化程序开发过程四、模块化程序开发过程1.为何采用模块编程为何采用模块编程模块化编程是一种软件设计方法。各模块程序要分别编写、编译和调模块化编程是一种软件设计方法。各模块程序要分别编写、编译和调试,最后将模块一起连接试,最后将模块一起连接/定位。模块化编程有以下优点:定位。模块化编程有以下优点:(1)模块化编程使程序开发更有效。模块化编程使程序开发更有效。上一页 下一页返回4.6 程程 序序 设设 计计(2)当同类的需求较多时,可把程序放入库中以备以后使用。模块当同类的需求较多时,可把程序放入库中以备以后使用。模块化编程使得要解决的问题与特定模块分离,很容易找到出错模块
45、,大化编程使得要解决的问题与特定模块分离,很容易找到出错模块,大大简化了调试。大简化了调试。2.模块化程序开发过程模块化程序开发过程模块化程序开发过程如模块化程序开发过程如图图4.11 所示。所示。六、库和连接器六、库和连接器/定位器定位器1.库库KeilC51 的编译库如的编译库如表表4.2 所示。所示。上一页 下一页返回4.6 程程 序序 设设 计计2.连接器连接器/定位器定位器连接器连接器/定位器是模块化编程的核心。定位器是模块化编程的核心。KeilC51 的的L51 程序可完成下程序可完成下列功能:列功能:(1)组合程序模块。组合程序模块。(2)组合段规则:组合段规则:所有具有相同名的
46、部分段必须有相同类型(所有具有相同名的部分段必须有相同类型(code、data、idata、xdata 或或bit)。)。组合段的长度不能超过存储区的物理长度。组合段的长度不能超过存储区的物理长度。每个组合的部分段的定位方法也必须相同。每个组合的部分段的定位方法也必须相同。绝对不相互组合,它们被直接复制到输出文件。绝对不相互组合,它们被直接复制到输出文件。上一页 下一页返回4.6 程程 序序 设设 计计(3)存储器分配。存储器分配。(4)采用覆盖技术使用数据存储器。采用覆盖技术使用数据存储器。(5)决定外部参考地址。决定外部参考地址。(6)绝对地址计算。绝对地址计算。(7)产生绝对目标文件。产
47、生绝对目标文件。(8)产生映像文件。映像文件包含下列信息:产生映像文件。映像文件包含下列信息:文件名和命令行参数。文件名和命令行参数。所有被处理模块的文件名和模块名。所有被处理模块的文件名和模块名。上一页 下一页返回4.6 程程 序序 设设 计计 一个包含段地址、类型、定位方法和名字的存储器分配表。该表一个包含段地址、类型、定位方法和名字的存储器分配表。该表可在命令行中用可在命令行中用NOMAP 参数禁止。参数禁止。段和符号的所有错误列表。列表文件末尾显示出所有出错的原因。段和符号的所有错误列表。列表文件末尾显示出所有出错的原因。一个包含输入文件中符号信息的符号表。该信息由一个包含输入文件中符
48、号信息的符号表。该信息由MODULES、SYMBOLS、PUBLICS和和LINES 名组成,名组成,LINES 是是C 编译器产生的编译器产生的行号。符号信息可用参数行号。符号信息可用参数NOSYMBOLS、NOPUBLICS 和和NOLINES 完全或部分禁止。完全或部分禁止。一个按字母顺序排列的有关所有一个按字母顺序排列的有关所有PUBLIC 和和EXTRN 符号的交叉参符号的交叉参考报告,其中显示出符号类型和模块名。第一个显示的模块名是定义考报告,其中显示出符号类型和模块名。第一个显示的模块名是定义了了PUBLIC 符号的模块,后面的模块名是定义了符号的模块,后面的模块名是定义了EXT
49、RN 符号的模块。符号的模块。在命令行输入参数在命令行输入参数IXREF 可产生此报告。可产生此报告。上一页 下一页返回4.6 程程 序序 设设 计计 在连接器在连接器/定位器运行期间检测到的错误同时显示在屏幕上和文件定位器运行期间检测到的错误同时显示在屏幕上和文件尾部。尾部。七、混合编程七、混合编程混合编程,即以不同语言编写的模块化编程。混合编程必须指定参数混合编程,即以不同语言编写的模块化编程。混合编程必须指定参数的传递规则。当组合在一起的程序部分以不同语言编写时,大多数是的传递规则。当组合在一起的程序部分以不同语言编写时,大多数是用汇编语言编写硬件有关的程序。用汇编语言编写硬件有关的程序
50、。1.函数名的转换函数名的转换函数名的转换如函数名的转换如表表4.3 所示。所示。上一页 下一页返回4.6 程程 序序 设设 计计2.参数传递参数传递参数传递寄存器选择如参数传递寄存器选择如表表4.4 所示。所示。3.根据硬件环境的配置根据硬件环境的配置KeilC51 编译器可根据不同的硬件环境由四个文件做出修改:编译器可根据不同的硬件环境由四个文件做出修改:STARTUP.A51、INIT.A51、PUTCHAR.C、GETCHAR.C。八、程序优化八、程序优化不经常重复的和包含用户接口的程序应该用高级语言编写。对小的、不经常重复的和包含用户接口的程序应该用高级语言编写。对小的、经常重复的紧