免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: javacool
打印 上一主题 下一主题

请教一个有关虚拟内存的问题 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2004-12-15 10:38 |只看该作者

请教一个有关虚拟内存的问题

楼上的意思 我明白 我的想法是 我的变量i是在中间声明的 所以他会不会是在函数调用后,在运行中才压栈, 这样它的地址就会发生变化
这边 我又换了一种写法 这次用不同函数调用次数来改变栈的大小这次证明了我的想法
以下是代码
#include <stdio.h>;

void fun()
{
        int k=15;
        printf(" %d\n",&k);
        k++;
}

void fun1()
{
        int j = 0;
        fun();
        j++;
}

void fun2()
{
        int c=0;
        fun1();
}
void main(int argc, char **argv)
{
       
        if(argc == 1)
                fun();
        else
                if(argc == 2)
                   fun1();
                else
                   fun2();
}
每次根据输入参数次数不同 调用不同数目的函数
的到的结果是
$test
1244924
$test  12
1244836
$test  12 23
1244748
每次参数k的地址(虚存地址)不同 且随着栈的增长(函数调用的增多) 参数K的地址变小

论坛徽章:
0
12 [报告]
发表于 2004-12-15 10:39 |只看该作者

请教一个有关虚拟内存的问题

补充一下,分配局部变量空间是在执行你的函数代码段之前完成的。这一点很重要

论坛徽章:
0
13 [报告]
发表于 2004-12-15 10:54 |只看该作者

请教一个有关虚拟内存的问题

nod

调用者:
是先压栈参数,然后调用call,最后调整esp出栈。

论坛徽章:
0
14 [报告]
发表于 2004-12-15 10:57 |只看该作者

请教一个有关虚拟内存的问题

嗯 楼上的说的有道理 再问一下
在函数中部声明的参数 编译后的代码也还是在进入函数代码端前就已经分配好的 还是 局部变量是栈中一个固定的区域运行时动态分配的(该区域不受push eax操作的影响)
这两种方法都可以解释 一开始代码中i变量地址不变的问题

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
15 [报告]
发表于 2004-12-15 11:01 |只看该作者

请教一个有关虚拟内存的问题

继续建议看C语言编译后的汇编代码,尤其是一般的函数框架。

论坛徽章:
0
16 [报告]
发表于 2004-12-15 11:18 |只看该作者

请教一个有关虚拟内存的问题

这个问题取决于编译器的实现,可以有两种做法:

1、见到局部变量后再分配。
2、计算一个函数所有局部变量占据空间的总和,一次分配。在函数运行过程中不再为局部变量做栈的调整。

第一种方法效率低,但容易实现。第二种方法效率高,但实现起来麻烦一些。gcc 在默认情况下,使用第二种策略。 至于vc,可以作如下观察:


  1. #include <stdio.h>;

  2. void main(int argc, char **argv)
  3. {
  4. int x;
  5. int count = argc;
  6. int y;
  7. while(count >; 0)
  8. {
  9. __asm
  10. {
  11. push eax;
  12. push eax;
  13. push eax;
  14. }
  15. count--;
  16. }
  17. {
  18. int i = 1; //在堆栈中分配i的空间
  19. printf ("%p\n", &x);              <====
  20. printf ("%p\n", &count);       <====
  21. printf ("%p\n", &y);     <====
  22. printf("%p\n", &i);    <====
  23. }
  24. count = argc;
  25. while(count >; 0)
  26. {
  27. __asm
  28. {
  29. pop eax;
  30. pop eax;
  31. pop eax;
  32. }
  33. count--;
  34. }
  35. }
复制代码

0012FF7C
0012FF78
0012FF74
0012FF70


显然是预先分配好的。

论坛徽章:
0
17 [报告]
发表于 2004-12-15 11:29 |只看该作者

请教一个有关虚拟内存的问题

原帖由 "javacool" 发表:
int count = argc;
while(count >; 0)
{
__asm
{
push eax;
push eax;
push eax;
}


此外,请注意 (count >;0)   的值总为 1

论坛徽章:
0
18 [报告]
发表于 2004-12-15 11:58 |只看该作者

请教一个有关虚拟内存的问题

>;>;1、见到局部变量后再分配。
我认为应该都是全部分配的吧,毕竟c不是解释执行的,编译器扫描代码的时候就会标记出哪些是局部变量然后一起分配好空间。

论坛徽章:
0
19 [报告]
发表于 2004-12-15 12:11 |只看该作者

请教一个有关虚拟内存的问题

比如

  1. f()
  2. {

  3. ...

  4.         { 《== local block
  5.                 int i;
  6.              ....
  7.         }

  8. }
复制代码

可以在进入 local block 时拨动栈指针,分配空间,离开块时把指针拨回去。相当于把 {} 看成不用跳转的函数。

我不清楚是否有编译器如此实现,但看上去十分可行。

这跟解释执行是不同的,指令都在编译时固定下来了。

论坛徽章:
0
20 [报告]
发表于 2004-12-15 12:53 |只看该作者

请教一个有关虚拟内存的问题

更正:

我仔细想了一下, 上面所说的 第一种 策略其实是十分糟糕的,原因在于:
{} 与函数 有一个很关键的不同:


  1. f()
  2. {
  3.         int  i;
  4.         ..........
  5.         { /* local block */
  6.                  int j;
  7.                  ..............
  8.          }
  9. }
复制代码


如上代码,变量  i 在  local block {} 中是可见的,也就是说,我们可以在
{} 中访问,修改 变量 i。这种情况在函数调用中不会出现。考虑到 local block
中可能会嵌套多个局部块,如果移动了记录栈的指针,将使得追踪各层局部变量的值变得很困难。如果这样,还不如一开始就 figure 出将要使用的空间,一次分配出去。

这个策略虽然糟糕,但却是可以实现的,因为  {} 块的个数总是可以预先知道,小心地把栈的变化记录下来就可以了。实际使用的编译器肯定不会使用这个策略。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP