预览加载中,请您耐心等待几秒...
1/5
2/5
3/5
4/5
5/5

在线预览结束,喜欢就下载吧,查找使用更方便

如果您无法下载资料,请参考说明:

1、部分资料下载需要金币,请确保您的账户上有足够的金币

2、已购买过的文档,再次下载不重复扣费

3、资料包下载后请先用软件解压,在使用对应软件打开

C51中的参数可变函数 作为引导的例子:假设要编写一个函数,来求n个数中最大的一个。函数的声明像下面这样: unsignedcharmax(unsignedn,…); 本文的目标就是实做这个函数。 C语言栈空间的处理方式:我们很容易看懂这样的代码 intsum(inta,intb) { return(a+b); } voidmain(void) { intx; x=sum(1,2);/*子函数的调用和返回*/ While(1); } 每一次子函数的调用和返回就伴随着一系列的压栈和出栈,但是“内存不可以泄露”,所以子函数返回后栈指针应该恢复到原来的位置,如下图所示: 有两种修正栈的办法:一种是在子函数sum内进行处理,另一种在调用子函数sum结束的地方处理。这也就是C语言函数的栈空间处理的两种方式_cdecl和_stdcall,您可以把_cdecl和_stdcall想象成两个函数,一调用就修正栈指针,如下图 _stdcall方式sum函数一旦编写好以后,修正栈的方法就固定了,以后函数的形参个数不能随意变化。如下图所示: 这个函数在调用结束后要把盏指针回调3个单位,调节指针的工作固定在sum子函数的代码内。 _cdecl方式sum函数内不做修正栈的工作,每次调用sum函数当返回时,编译器都重新帮助sum函数再修正一次栈空间,这样就允许了sum函数形参个数变化,反正这时sum函数又不操心入栈出栈的问题,它只关心运算处理,编译器知道这次调用入栈了多少,应该出栈多少,如下图示: _stdcall方式节约了ROM(计算机专业的人叫代码段),但是却让sum函数的形参个数不可以变化。_cdecl方式浪费了ROM,但是函数的形参个数可以变化。所以我们在VC++里会看到printf这样重要的函数,都是_cdecl方式的,但是动态链接库的函数一般都是_stdcall方式的。前者是实际需要,形参必须可以变化;后者因为大量被使用,必须考虑节约ROM(代码段)。 但是在单片机里大家不必操心这些,KeilC51有自己的入栈出栈方式,参数可变函数能够成功运行。 栈的指针:想象一下假设我们编写好了一个参数可变函数,然后去调用它为我们工作。就像这样function(a,b,c,d,e),调用前形式参数被压入栈内,在function代码内部可以用栈指针去寻找这些参数,然后去使用。一提到栈的指针,大家马上就想到了sp,但是这样不好。要动用汇编指令,更麻烦的是汇编和C语言的结合,这是我们不想看到的场面。 C语言里有其他办法解决这个问题,那就是利用标准库stdarg.h。这里面的一个数据类型和三个“函数”是我们最关心的: va_list//注意这是一个数据类型,就如同char va_start(形参1,形参2); va_arg(形参1,形参2); va_end(形参); 它们的用途马上就解释。 实做unsignedcharmax(unsignedn,…)函数: 这个函数就像他的名字所描述的一样,求n个数中最大的一个。假设我们编写好了这个函数,我们就可以去调用了: voidmain(void) { unsignedcharM; M=max(5,20,45,55,80,95); while(1);//51单片机停机 } M自然是返回95,调用这个函数前,5、20、45、55、80、95先被压栈,如下图所示: 要操作这些数据,我们需要一个指向栈空间的指针pStack,我们可以利用下面方法定义这个指针: va_listpStack; 下面我们想让pStack指向20,如下图: 方法是,调用函数va_start(pStack,n)。您也许很诧异倒低n是什么,那么我把全部的代码拷贝过来给您看看吧,它是这样的: va_start(pStack,n)很古怪,但是这个函数确实就是这么用的,这倒不是需要n的值,而是需要n这个符号。这样pStack马上就指向了n后续的参数。然后您一定想引用这个指针(*pStack)了吧?不行,都不知道pStack指向了什么类型的数据。我们需要利用函数 va_arg(pStack,unsignedchar); 这个函数依然很古怪,(1)这个函数使pStack感觉自己指向的是unsignedchar类型的数据 (2)这个函数把栈指针pStack所指向的内容返回来,并且按(1)的要求认为数据是unsignedchar (3)这个函数还调整指针pStack++,按(1)的要求跳过一个unsignedchar类型的数据单元 这个函数自然也可以这样用va_arg(pStack,unsignedint),您能明白意思吧? 一切的工作都做完了以后,我们要释放pStack指针,也就是利用函数va_end(pStack)