打印

请教一下有关局部变量与堆栈的问题?

[复制链接]
5266|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gnail092|  楼主 | 2011-6-5 22:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我知道在函数X中定义的局部变量被压入堆栈,函数返回时,退出堆栈,局部变量就不存在,变量窗口的值显示“out of  scope",我现在的疑问就是说如果在这个函数里再去调用另一个函数Y时,在程序运行到被凋函数Y时,在函数X定义的局部变量是否还是存在的,因为我在函数Y里设了个断点,运行到断点时,函数X的局部变量也是显示“out of  scope",然后返回到函数X时,局部变量的值还是调用函数Y前的值,是不是说这个函数X的局部变量在调用函数Y的过程一直是存在的?也就是说调用函数Y后函数X的局部变量有没有推出堆栈,跟函数X返回后局部变量退出堆栈的情况应该不一样的把?
描述的有点复杂,请大家帮我耐心解答以下

相关帖子

沙发
yuyi21ic| | 2011-6-5 23:03 | 只看该作者
x函数里的变量是在执行x这个函数的return后才销毁吧,因此Y函数在X函数中被调用,那么Y函数就隶属于之前那个变量的作用域。当然,Y函数里的变量名字不应该与x函数里的那个变量名字相同,否则~~~~~。

使用特权

评论回复
板凳
gnail092|  楼主 | 2011-6-6 00:13 | 只看该作者
那为什么我在函数Y里设了个断点,运行到断点时,函数X的局部变量也是显示“out of  scope"

使用特权

评论回复
地板
sysdriver| | 2011-6-6 13:24 | 只看该作者
x函数里的变量是在执行x这个函数的return后才销毁吧,因此Y函数在X函数中被调用,那么Y函数就隶属于之前那个变量的作用域。当然,Y函数里的变量名字不应该与x函数里的那个变量名字相同,否则~~~~~。 ...
yuyi21ic 发表于 2011-6-5 23:03

不是每个函数都有return的,你可以描述成函数结束。即使同名也没有关系,也不会报错,只不过外部在内部中不起作用罢了。

使用特权

评论回复
5
sysdriver| | 2011-6-6 13:42 | 只看该作者
那为什么我在函数Y里设了个断点,运行到断点时,函数X的局部变量也是显示“out of  scope"
gnail092 发表于 2011-6-6 00:13

程序的问题,描述时可以采用程序的方式,不然,语言有点难理解。

void Y(void)
{
       unsigned char k;

       k = 6;
}

void X(void)
{
       unsigned char i;

       i = 1;
       Y();
}

void main(void)
{
       X();
       while(1);
}

拿局部变量 i 来说,在调用Y过程中,i 的值是一直存在在堆栈中的。你看不见,是因为 i 的作用域是在X中,虽然Y是在X中被调用,但Y的作用域不在X中,调用时已经跳转作用域了。如果你想在Y中引用 i 的值,你可以用函数参数的方式。如果你想在Y中改变 i 的值,传递的参数要是 i 的地址。

使用特权

评论回复
6
yuyi21ic| | 2011-6-6 13:42 | 只看该作者
不是每个函数都有return的,你可以描述成函数结束。即使同名也没有关系,也不会报错,只不过外部在内部中不起作用罢了。
sysdriver 发表于 2011-6-6 13:24
我后面的~~~~就表示你后半句的意思。

使用特权

评论回复
7
hzwenli| | 2011-6-6 21:42 | 只看该作者
编译器设置成LARGE模式可以解决该问题

使用特权

评论回复
8
刘前辈| | 2011-6-7 16:26 | 只看该作者
2#
当然,Y函数里的变量名字不应该与x函数里的那个变量名字相同,否则~~~~~。


2个函数的局部变量当然可以同名。互不干扰的。

void Y(void)
{
       unsigned char k;
       k = 6;
}

void X(void)
{
       unsigned char k;
       k = 1;
       Y();
}

void main(void)
{
       X();
       while(1);
}

使用特权

评论回复
9
yewuyi| | 2011-6-7 16:36 | 只看该作者
你只需要弄明白什么叫着变量的生存期即可完全明白。


自然也就明白了为什么可以同名。

使用特权

评论回复
10
刘前辈| | 2011-6-7 16:38 | 只看该作者

编译结果

本帖最后由 刘前辈 于 2011-6-7 16:40 编辑

$NOMOD51

?PR?Y?TEST5          SEGMENT CODE INBLOCK
?DT?Y?TEST5          SEGMENT DATA OVERLAYABLE
?PR?X?TEST5          SEGMENT CODE INBLOCK
?DT?X?TEST5          SEGMENT DATA OVERLAYABLE
?PR?main?TEST5       SEGMENT CODE INBLOCK
        EXTRN        CODE (?C_STARTUP)
        PUBLIC        main
        PUBLIC        X
        PUBLIC        Y

        RSEG  ?DT?X?TEST5
?X?BYTE:
          k?141:   DS   1

        RSEG  ?DT?Y?TEST5
?Y?BYTE:
          k?040:   DS   1
; void Y(void)

        RSEG  ?PR?Y?TEST5
Y:
; {
;     unsigned char k;
;        k = 6;
                        
        MOV          k?040,#06H
; }
        RET         
; END OF Y

;
; void X(void)

        RSEG  ?PR?X?TEST5
X:
; {
;        unsigned char k;

;        k = 1;
                        
        MOV          k?141,#01H    ; 调用Y()函数时,X()局部变量显然没有被覆盖,也不在堆栈区。——在动态可覆盖、共享存储区。

;        Y();
                        
        AJMP         Y
; END OF X

; }
;
; void main(void)

        RSEG  ?PR?main?TEST5
main:
                        
; {
                        
;        X();
                        
        ACALL        X
?C0003:
;        while(1);
                        
        SJMP         ?C0003
; END OF main

        END

、、

使用特权

评论回复
11
gnail092|  楼主 | 2011-6-8 11:07 | 只看该作者
9# yewuyi

进入函数Y时函数X变量的生存期还存在的吧,只不过作用域不在,所以可以同名吧

使用特权

评论回复
12
gnail092|  楼主 | 2011-6-8 11:08 | 只看该作者
本帖最后由 gnail092 于 2011-6-8 11:11 编辑

10# 刘前辈

调用Y()函数时,X()局部变量显然没有被覆盖,也不在堆栈区。——在动态可覆盖、共享存储区。
你说的“在动态可覆盖、共享存储区”具体是什么,各种单片机都这样吗,局部变量不就是存在堆栈中吗

使用特权

评论回复
13
xwj| | 2011-6-8 11:18 | 只看该作者
LZ ,你要先弄明白什么叫着变量的生存期和作用域。

简单的说,就是函数自己的局部变量都是他自己私有的,别人不能访问。
就好比你租了一套房子,你的房间名有一个叫做“卧室”,这个“卧室”可是你自己私有的,可不是别人能够随便访问、使用的。同时,就算别人家也有个叫“卧室”的房间,但实际上和你的“卧室”完全是两码事。

当然,函数返回后就相当于房子退租了,资源被释放,你用过的房子系统又能(又会)随机的租给另一个申请的人了。

使用特权

评论回复
14
xwj| | 2011-6-8 11:24 | 只看该作者
再延伸一下:

至于上面说的“可不是别人能够随便访问、使用的。”而不说“不是别人能够访问、使用的。”
这是因为一般情况下大家都是按照正常的渠道访问你的房间(变量、资源),但不排除特殊的访问,比如小偷、比如房东等。

程序也是一样,正常编译的代码编译系统会自动进行覆盖分析,避免错误的访问、和错误的重复使用,但是却可以用指针、绝对地址等访问任意绝对位置的存储器,这就相当于调用房东权限了。
而如果别的函数乱用指针、或者数组使用越界,也是可能非法访问到你的房间的,那就是BUG了

使用特权

评论回复
15
yff1030| | 2011-6-8 11:27 | 只看该作者
13楼说的好

使用特权

评论回复
16
gnail092|  楼主 | 2011-6-8 12:03 | 只看该作者
14# xwj

这位高手能不能说一下覆盖分析是怎么避免错误的访问、和错误的重复使用

使用特权

评论回复
17
刘前辈| | 2011-6-8 12:19 | 只看该作者
  12#
调用Y()函数时,X()局部变量显然没有被覆盖,也不在堆栈区。——在动态可覆盖、共享存储区。
你说的“在动态可覆盖、共享存储区”具体是什么,各种单片机都这样吗,局部变量不就是存在堆栈中吗


至少C51裸奔程序是这样分配:RAM区由低到高,分别为——静态全局变量区--动态可覆盖/共享局部变量区--堆栈区;  12楼说的是RTOS ?


、、

使用特权

评论回复
18
lxyppc| | 2011-6-8 12:53 | 只看该作者
14# xwj  

这位高手能不能说一下覆盖分析是怎么避免错误的访问、和错误的重复使用
gnail092 发表于 2011-6-8 12:03

编译器内部会生成一张call graph,函数调用表,根据这张表看局部变量有无覆盖的可能

使用特权

评论回复
19
gnail092|  楼主 | 2011-6-9 15:34 | 只看该作者
17# 刘前辈

好像就51是这样的,通过覆盖分析, 可以共享局部变量的地址空间.,AVR还分软件堆栈和硬件堆栈,下面这篇**就讲到了http://hi.baidu.com/michael1517/blog/item/e687351634fcb90c962b43aa.html

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

68

帖子

1

粉丝