收藏 分销(赏)

第八讲-C语言函数与预处理力天手把手教你学单片机之优秀文档.ppt

上传人:二*** 文档编号:10295970 上传时间:2025-05-18 格式:PPT 页数:34 大小:1.69MB
下载 相关 举报
第八讲-C语言函数与预处理力天手把手教你学单片机之优秀文档.ppt_第1页
第1页 / 共34页
本文档共34页,全文阅读请下载到手机保存,查看更方便
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,版权:力天电子,主讲人:尹延辉,单击此处编辑母版标题样式,单击此处编辑母版文本样式,*,手把手教你学,51,单片机,之,MCS-51,基础篇,主 讲,:,尹延辉,策 划:张 勇,开发板:,LT-Super51,QQ,群:,31646346,网址:,E-Mail,:,litianmcu,基础篇 第四讲,C,语言函数与预处理,本讲内容提要,概述,函数定义的一般形式,函数参数和函数的值,局部变量和全局变量,预处理命令概述,宏定义,条件编译,文件包含,多文件的程序,温故知新,C,的三种语句结构,C,语句概述,C,语句用于实现数据操作,控制语句、函数调用语句、表达式语句等等,程序的三种基本结构,顺序结构、选择结构、循环结构,此三种之组合可以处理任何复杂问题,顺序结构程序设计,按顺序执行一系列的语句,选择结构程序设计,通过判断条件真假,(,非,0,,,0),决定程序的走向。,if,与,switch,结构,循环结构程序设计,while,、,do.while,、,for,三种形式的循环结构,释疑解惑,C,的三种语句结构,填空题,C,语言三种基本的语句结构分别是,顺序结构,、,选择结构,、,循环结构,。,两种基本的选择结构语句分别是基于,if,语句和,switch.case,语句。,三种最常用的循环结构语句分别是,while,语句、,do.while,语句、,for,语句。,有,char a=a;,则以下逻辑表达式的结果分别是,(,真、假,),:,ab,假,;,aB,真,;,(a0)&(a0)|(aA),真,.,实验题,设计,C,语言程序,求,220,的累加和,并将运算结果显示在流水灯上。,设计,C,语言程序,实现以下现象:板上流水灯显示的,8,位二进制数每隔,1,秒自增,1,,从,0,开始增至,255,时,下一个数变回,0,继续自增。,新语新知,C,函数概述,一个较大的程序一般应分为若干个程序模块,每一个模块用来实现一个特定的功能。所有的高级语言中都有子程序这个概念,用子程序实现模块的功能。在,C,语言中,子程序的作用是由函数完成的。一个程序可由一个主函数和若干个函数构成。由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。图,1,是一个程序中函数调用的示意图。,在程序设计中,常将一些常用的功能模块编写成函数,放在函数库中供公共选用。要善于利用函数,以减少重复编写程序段的工作量。,图,1,新语新知,C,函数概述,C,函数调用举例,void,main,(,void,),LED_BIT=,1,;,/74HC573,的,L,引脚置高电平,使其处于直通状态,P0=0 xff;,/8,位流水灯全亮,delay_1s,(),;,/,延时,1,秒,P0=0 x00;,/8,位流水灯全灭,delay_1s,(),;,/,延时,1,秒,P0=0 xff;,/8,位流水灯全亮,while,(,1,),;,/,条件总为真,死循环,新语新知,C,函数概述,关于,C,函数的,6,点说明,一个源程序文件由一个或多个函数组成。一个源程序文件是一个编译单位,即以源程序为单位进行编译,而不是以函数为单位进行编译。,一个,C,程序由一个或多个源程序文件组成。对较大的程序,一般不希望全放在一个文件中,而将函数和其他内容(如预定义)分别放在若干个源文件中,再由若干源文件组成一个,C,程序。这样可以分别编写、分别编译,提高调度效率。一个源文件可以为多个,C,程序公用。,C,程序的执行从,main,函数开始,调用其他函数后流程回到,main,函数,在,main,函数中结束整个程序的运行。,main,函数是系统定义的。,所有函数都是平行的,即在定义函数时是互相独立的,一个函数并不从属于另一函数,即函数不能嵌套定义,函数间可以互相调用,但不能调用,main,函数。,全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。,(Y,X)Y|=(1 y)z,x;,else z=y;,return(z);,新语新知,函数定义的一般形式,这是一个求,x,和,y,二者中大者的函数,笫,1,行第一个关键字,char,表示函数值是字符型的。,max,为函数名。括号中有两个形式参数,x,和,y,,它们都是字符型的。在调用此函数时,主调函数把实际参数的值传递给被调用函数中的形式参数,x,和,y,。花括弧内是函数体,它包括声明部分和语句部分。在声明部分定义所用的变量,此外对将要调用的函数作声明在函数体的语句中求出,z,的值(为,x,与,y,中大者),,return(z),的作用是将,z,的值作为函数值带回到主调函数中。,return,后面的括弧中的值,(z),作为函数带回的值(或称函数返回值)。在函数定义时已指定,max,函数为整型,在函数体中定义,z,为整型,二者是一致的,将,z,作为函数,max,的值带回调用函数。,新语新知,函数参数和函数的值,形式参数和实际参数,在调用函数时,大多数情况下,主调函数和被调用函数之间有数据传递关系。这就是前面提到的有参函数。前面已提到:在定义函数时函数名后面括弧中的变量名称为“形式参数”(简称“形参”),在主调函数中调用一个函数时,函数名后面括弧中的参数,(,可以是一个表达式,),称为“实际参数”(简称“实参”)。,main(),int,a=4,b=6,c;,c=max(,a,b,);,P0=c;,while(1);,但若该外部变量与其他文件的变量同名时,就会出现问题,降低了程序的可靠性和通用性。,例如:sbit(P0,a+b),在宏展开时并不求a+b的值,而只将实参字符“a+b”代替形参r。,如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。,两种基本的选择结构语句分别是基于if语句和switch.,温故知新C的三种语句结构,这是由系统提供的,用户不必自己定义这些函数,可以直接使用它们。,手把手教你学51单片机 之MCS-51基础篇,提示:循环左移的意思是将左边移出的位补在右边空出的位上;,用以解决用户的专门需要。,P0=0 xff;/8位流水灯全亮,有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。,所谓“文件包含”处理是指一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。,if(xy)zx;,C提供的预处理功能主要有以下三种:_,_,_。,通常,#define命令写在文件开头,函数之前,作为文件一部分,在此文件范围内有效。,新语新知C函数概述,新语新知,函数参数和函数的值,形式参数和实际参数,max,后面括弧内的,a,、,b,是实参。,a,和,b,是,main,函数中定义的变量,,x,和,y,是函数,max,中的形式参数。通过函数调用,使两个函数中的数据发生联系。,实参可以是常量、变量或表达式,如:,max(3,,,a,b);,但要求它们有确定的值。在调用时将实参的值赋给形参。,新语新知,函数参数和函数的值,形式参数和实际参数,C,语言规定,实参变量对形参变量的数据传递都是“值传递”,即单向传递,只由实参传给形参,而不能由形参传回来给实参。,在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数的实参的值。例如,若在执行函数过程中,x,和,y,的值变为,10,和,15,,而,a,和,b,仍为,2,和,3,新语新知,函数参数和函数的值,函数的返回值,通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。例如,,max(2,3),的值是,3,,,max(5,2),的值是,5,。赋值语句将这个函数值赋给变量,c,。几点说明:,函数的返回值是通过函数中的,return,语句获得的。,return,语句将被调用函数中的一个确定值带回主调函数中去。一个函数中可以有一个以上的,return,语句,执行到哪一个,return,语句,哪一个语句起作用。,如果函数值的类型和,return,语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。,为了明确表示“不带回值”,可以用“,void”,定义“无类型”(或称“空类型”)。,新语新知,局部变量和全局变量,局部变量,在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的。这称为“局部变量”。例如如果在,main,函数中使用变量,x,或,y,会提示未定义的变量。几点说明:,主函数,main,中定义的变量,a,,,b,也只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效。,不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰。,形式参数也是局部变量。例如,max,函数中的形参,x,,,y,也只在,max,函数中有效,其他函数不能调用。,新语新知,局部变量和全局变量,全局变量,前已介绍,程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量,外部变量是全局变量,(,也称全程变量,),。全局变量可以为本文件中其他函数所共用。它的有效范围为,从定义变量的位置开始到本源文件结束,。,新语新知,局部变量和全局变量,全局变量的若干注意事项,设全局变量的作用是增加了函数间数据联系的渠道。由于同一文件中的所有函数都能引用全局变量的值,因此如果在一个函数中改变了全局变量的值,就能影响到其他函数,相当于各个函数间有直接的传递通道。由于函数的调用只能带回一个返回值,因此有时可以利用全局变量增加与函数联系的渠道,,从函数得到一个以上的返回值,。,建议不在必要时不要使用全局变量,因为:,全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。,它使函数的通用性降低了,因为函数在执行时要依赖于其所在的外部变量。如果将一个函数移到另一个文件中,还要将有关的外部变量及其值一起移过去。但若该外部变量与其他文件的变量同名时,就会出现问题,降低了程序的可靠性和通用性。,新语新知,局部变量和全局变量,全局变量的若干注意事项,使用全局变量过多,会降低程序的清晰性,人们往往难以清楚地判断出每个瞬时各个全局变量的值。在各个函数执行时都可能改变全局变量的值,程序容易出错。因此,要限制使用全局变量。,如果在同一个源文件中,全局变量与局部变量同名,则在局部变量的作用范围内,全局变量被“屏蔽”,即它不起作用。,char x,char y;,char max(char x,char y),char z;/,声明部分,if(xy)z,x;,else z=y;,return(z);,main(),int a=4,b=6,c;,c=max(a,b);,P0=c;,while(1);,新语新知,预处理命令概述,背景知识,C,标准规定可以在,C,源程序中加入一些“预处理命令”,,以改进程序设计环境,提高编程效率,但是它不是,C,语言本身的组成部分。必须在对程序进行通常的编译之前,先对程序中这些特殊的命令进行“预处理”,即根据预处理命令对程序作相应的处理。,例如,若程序中用,#define,命令定义了一个符号常量,A,,则在预处理时将程序中所有的,A,都置换为指定的字符串。若程序中用,#include,命令包含一个文件,”reg52.h”,,则在预处理时将,文件中的实际内容代替该命令。然后再由编译程序对预处理后的源程序进行通常的编译处理,得到可供执行的目标代码。,不少用户误认为预处理命令是,C,语言的一部分,甚至以为它们是,C,语句,这是不对的。必须正确区别预处理命令和,C,语句、区别预处理和编译,才能正确使用预处理命令。,新语新知,预处理命令概述,背景知识,C,提供的预处理功能主要有以下三种:,宏定义,条件编译,文件包含,分别用宏定义命令、文件包含命令、条件编译命令来实现。为了与一般,C,语句相区别,这些命令以符号“,#,”开头。,新语新知,宏定义,不带参数的宏定义,用一个指定的标识符,(,即名字,),来代表一个字符串,它的一般形式为,#define,标识符字符串。例如,:,#define LED_ON 0 xFF,#define LED_OFF 0 x00,它的作用是指定用标识符,LED_ON,来代替“,0 xFF,”这个字符串,用标识符,LED_OFF,来代替“,0 x00,”这个字符串,在编译预处理时,将程序中在该命令以后出现的所有的,LED_ON,都用“,0 xFF,”代替,所有,LED_OFF,都用“,0 x00,”代替。这种方法使用户能以一个简单的名字代替一个长的字符串,因此把这个标识符,(,名字,),称为“宏名”,在预编译时将宏名替换成字符串的过程称为“宏展开”。,#define,是宏定义命令。,新语新知,宏定义,#define LED_ON 0 xFF,#define LED_OFF 0 x00,void main(void),led_enable();/74HC573,的,L,引脚置高电平,使其处于直通状态,while(1)/,条件总为真,死循环,P0=LED_ON;/8,位流水灯全亮,my_delay1s();/1,秒延时,P0=LED_OFF;/8,位流水灯全灭,my_delay1s();/1,秒延时,新语新知,宏定义,不带参数的宏定义,使用宏名代替一个字符串,可以减少程序中重复书写某些字符串的工作量。例如,如果不定义,LED_ON,代表,0 xFF,,则在程序中要多处出现,0 xFF,,不仅麻烦,而且容易写错,(,或敲错,),,用宏名代替,简单不易出错,因为记住一个宏名,(,它的名字往往用容易理解的单词表示,),要比记住一个无规律的字符串容易,而且在读程序时能立即知道它的含义,当需要改变某一个常量时,可以只改变,#define,命令行,一改全改。,宏定义是用宏名代替一个字符串,也就是作简单的置换,不作正确性检查。如果写成,define LED_ON 0 xXF,预处理时也照样代入,不管含义是否正确。也就是说预编译时不作任何语法检查。只有在编译已被宏展开后的源程序时才会发现错误并报错。,新语新知,宏定义,宏定义不是,C,语句,不必在行末加分号。如果加了分号则会连分号一起进行置换。,define LED_ON 0 xFF;,.,P0=LED_ON-1;,会被替换成,P0=0 xFF;1;,显然会出现语法错误。,#define,命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束。通常,,#define,命令写在文件开头,函数之前,作为文件一部分,在此文件范围内有效。,宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,只作字符替换,不分配内存空间。,新语新知,宏定义,在进行宏定义时,可以引用已定义的宏名,可以层层置换。,define LED_ON 0 xFF,#define led_all_on()P0=LED_ON,.,led_all_on();,经过宏展开后变为,P0=0 xFF;,新语新知,宏定义,带参数的宏定义,宏定义不是进行简单的字符串替换,还要进行参数替换。其定义的一般形式为,#define,宏名,(,参数表,),字符串,字符串中包含在括弧中所指定的参数。如:,#define sbit(Y,X)Y|=(1 X),.,sbit(P0,2);,/,实现对,P0,口,位置,1,宏展开后,P0|=(1 2);,新语新知,宏定义,使用参数宏的几个注意事项,对带参数的宏的展开只是将语句中的宏名后面括号内的实参,字符串,代替,#define,命令行中的形参。,在宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。,#define sbit (Y,X)Y|=(1 X),.,sbit(P0,2);,宏展开后,(Y,X)Y|=(1 X)(P0,2);,显然不对。,新语新知,宏定义,参数宏与函数的联系与区别,函数调用时,先求出实参表达式的值,然后代入形参。而使用带参的宏只是进行简单的字符替换。例如:,sbit(P0,a+b),,在宏展开时并不求,a+b,的值,而只将实参字符“,a+b,”代替形参,r,。,函数调用是在程序运行时处理的,分配临时的内存单元。而宏展开则是在编译时进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。,对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换。而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时代入指定的字符即可。宏定义时,字符串可以是任何类型的数据。,宏替换不占运行时间,只占编译时间。而函数调用则占运行时间,(,分配单元、保留现场、值传递、返回,),。,新语新知,条件编译,参数宏与函数的联系与区别,一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。,条件编译命令有以下,3,种形式:,#ifdef,标识符,程序段,1,#else,程序段,2,#endif,#ifndef,标识符,程序段,1,#else,程序段,2,#endif,#if,标识符,程序段,1,#else,程序段,2,#endif,新语新知,“文件包含”处理,参数宏与函数的联系与区别,所谓“文件包含”处理是指一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。,C,语言提供了,#include,命令用来实现“文件包含”的操作。其一般形式为,#include“,文件名,”,或,#include ,新语新知,“文件包含”处理,参数宏与函数的联系与区别,上图表示“文件包含”的含意。图,(a),为文件,,它有一个,#include,命令,然后还有其他内容,(,以,A,表示,),。图,(b),为另一文件,,文件内容以,B,表示。在编译预处理时,要对,#include,命令进行“文件包含”处理:将,的全部内容复制插入到,#include,命令处,即,被包含到,中,得到图,(c),所示的结果。在编译中,将“包含”以后的,file1.c(,即图,(c),所示,),作为一个源文件单位进行编译。,“文件包含”命令是很有用的,它可以节省程序设计人员的重复劳动。,return语句将被调用函数中的一个确定值带回主调函数中去。,在C语言中,子程序的作用是由函数完成的。,然后再由编译程序对预处理后的源程序进行通常的编译处理,得到可供执行的目标代码。,while(1);/条件总为真,死循环,h命令处,即被包含到中,得到图(c)所示的结果。,新语新知多文件的程序,c=max(a,b);,要善于利用函数,以减少重复编写程序段的工作量。,在声明部分定义所用的变量,此外对将要调用的函数作声明在函数体的语句中求出z的值(为x与y中大者),return(z)的作用是将z的值作为函数值带回到主调函数中。,按顺序执行一系列的语句,LED_BIT=1;/74HC573的L引脚置高电平,使其处于直通状态,新语新知局部变量和全局变量,delay_1s();/延时1秒,C标准规定可以在C源程序中加入一些“预处理命令”,以改进程序设计环境,提高编程效率,但是它不是C语言本身的组成部分。,如果加了分号则会连分号一起进行置换。,实参可以是常量、变量或表达式,如:,设计一个函数完成以下功能:计算一个字符型变量循环左移任意位之后的值。,新语新知,多文件的程序,头文件的制作方法,建立文件,,将用到的功能封装成函数放在该文件当中,全局变量作用域仅限于本文件。将,添加到,Keil,工程的源程序文件列表中。,建立文件,,添加条件编译命令,然后在第二行添加头文件内容。,#ifndef _ABC_,/,此处添加头文件内容,#endif,头文件中尽量不要有全局变量,将,文件中的函数的声明放在,中。,将宏定义也放在,中。,动手实战,课后习题,填空题,C,语言函数的实参可以把自身数值传递给形参,形参,_(,可以,不可以,),把自身数值传递给实参。,在函数内部定义的变量称为,_,变量。作用域可以达到整个文件的变量是,_,变量。,C,提供的预处理功能主要有以下三种:,_,,,_,,,_,。,预处理中的,_,可以实现类似函数的功能。,实验题,设计一个函数完成以下功能:计算一个字符型变量循环左移任意位之后的值。提示:循环左移的意思是将左边移出的位补在右边空出的位上;本函数需要,2,个参数,一个是待移位的原始数据,一个是循环左移的位数;一个返回值,返回第一个参数循环移位后得到的结果。,将第三讲中的,1,秒延时函数封装在一个名为,delay.c,文件中,并设计一个头文件使该函数可以正常被外部调用。,
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传
相似文档                                   自信AI助手自信AI助手

当前位置:首页 > 通信科技 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服