首页 理论教育 Arduino单片机实战开发技术:实现数据传入和传出

Arduino单片机实战开发技术:实现数据传入和传出

时间:2023-10-23 理论教育 版权反馈
【摘要】:了解数据是如何在函数和主程序之间来回传递是非常重要的。使用传递值将数据传递给函数时,发送给函数的是变量的右值,而不是变量本身。图6-5压入数据的堆栈当堆栈达到此状态时,程序将控制权转移到IsLeapYear()函数代码。你可以将堆栈视为来自外部世界的数据的背包。TOS弹出以反映已移除的两个板。尽管所有这些将数据推送到堆栈上或从堆栈上弹出的操作看起来像是杀死蚂蚁的氢弹,但你必须了解数据是如何传递到函数,并从函数调用返回的。

Arduino单片机实战开发技术:实现数据传入和传出

了解数据是如何在函数和主程序之间来回传递是非常重要的。下面简要地描述一下,当函数中传递参数时会出现两种情况,按值传递和按址传递。下面我们先学习按值传递机制。

看看清单6-2中的代码:

if(IsLeapYear(year)){

将IsLeapYear()的函数调用放在if语句的expression1。让我们看看这是怎么回事。

首先,要注意的是变量名year被传递给IsLeapYear()函数。这是一个被称为传递值的示例。使用传递值将数据传递给函数时,发送给函数的是变量的右值,而不是变量本身。在这里换句话说,年值(即其右值)的临时副本将被复制并在调用中使用IsLeapYear()。为了便于讨论,让我们假设这个年份等于2012年。

为使IsLeapYear()函数的代码获取值2012的机制称为堆栈。堆栈是内存的一小部分,如图6-3所示,其中TOS代表堆栈顶部,BOS代表堆栈底部。如果堆栈是空的,TOS和BOS是相等的……它们在内存中具有相同的地址

图6-3 数值堆栈

请注意,现在假设我们将一个内存地址推送到堆栈上。让我们进一步假设所有内存地址对于开发板为4字节值。我们把一个内存地址(40000)推到堆栈上,堆栈现在如图6-4所示。将内存地址推到堆栈上会导致BOS向下下沉4字节,如图6-4所示。也就是说,BOS向下沉入4个位置,为4字节数据让路内存地址(40000),而TOS保持不变。

图6-4 堆栈

让我们进一步假设内存地址40000表示保存从IsLeapYear()函数调用返回后要执行的下一条程序指令。那么,我们如何将年值的副本传递到函数中呢?正如你可能猜到的,我们推出了将一年的右值添加到堆栈中。因为year是int,所以该值(2012)的副本需要2字节的存储空间。这将堆栈的图片更改为图6-5所示(这条分界线比我们想象的要重一些,显示两个数据项之间的轮廓)。

图6-5 压入数据的堆栈

当堆栈达到此状态时,程序将控制权转移到IsLeapYear()函数代码。编译器确切地知道在内存中跳转到哪里开始执行函数代码。也就是说,IsLeapYear()与程序中的所有其他数据对象一样具有左值。你可以将堆栈视为来自外部世界的数据的背包。(www.xing528.com)

IsLeapYear()的签名告诉函数代码如何将来自外部世界的数据打包到背包中。即:

int IsLeapYear(int yr)

使代码首先查找存储在堆栈上的int数据。它知道堆栈上有一个int,因为参数列表(int yr)告诉它堆栈上放置了什么。因为每个int需要2字节的存储空间,代码进入TOS的内存地址,获取2字节的数据(即2012),并将它们复制到临时变量yr的右值中。在将2012赋值为yr之后,调整TOS以反映堆栈中弹出的2个字节。TOS弹出以反映已移除的两个板。这意味着堆栈将再次出现如图6-4所示内容。

现在执行函数的语句体代码。因为2012年是闰年,所以if语句表示函数必须将值1返回给调用方。要做到这一点,代码会在下一个堆栈中的4个字节,这是程序在调用后恢复执行的返回地址IsLeapYear()已完成(即内存地址40000)。该内存地址会弹出到程序指令指针。你可以将程序指令指针看作是告诉程序在哪里找到下一个程序语句的指令。一旦4字节被“炸掉”在指令指针中,代码将2字节的返回值放在堆栈上。现在堆栈看起来像图6-6。

图6-6 变化后的堆栈

因为2012年是闰年,所以值1被推到堆栈上。函数的类型说明符告诉我们返回值是int,因此需要2字节的堆栈空间。换句话说,背包中的值1现在存储为int。

由于指令指针保留下一条程序指令所在的内存位置,因此程序将执行判断语句的分支语句:

if(IsLeapYear(year)){

但是,由于代码现在是在调用IsLeapYear()后执行指令,因此该语句看起来好像是编写为:

if(1){

代码以这种方式显示的原因是对IsLeapYear()的调用已完成,并且返回值(即1)已由函数的语句块代码确定。函数的类型说明符告诉我们int位于堆栈上(即,在背包中)。就是背包的内容已作为int从堆栈中弹出,并成为if的expression1表达式。由于非零值被解释为逻辑真,因此程序将通过串行传输向PC端返回数据,并告知用户2012年是闰年。

尽管所有这些将数据推送到堆栈上或从堆栈上弹出的操作看起来像是杀死蚂蚁的氢弹,但你必须了解数据是如何传递到函数,并从函数调用返回的。还需要注意的是,它是发送给IsLeapYear(),而不是其左值,这就是所谓的按值传递。因为IsLeapYear()没有任何线索当year存储在内存中时,IsLeapYear()无法更改year本身的右值。通过“按值”表示只向函数发送参数的右值,而不是其左值。只要IsLeapYear()仍然不知道左值,函数就不可能意外更改在loop()中返回年份的值。按值传递是一种保护的机制(即封装),避免来自外部的原始数据被破坏。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈