精华内容
下载资源
问答
  • 一、的地址增长方向要想验证区究竟是开口向上还是开口向下,都进行先压变量a再压变量b的操作,若a的首地址比b的首地址大则说明开口向下,若b的首地址比a的首地址大,则说明开口向上,下面就用代码来验证一下:...

    一、栈区的地址增长方向

    这里写图片描述

    要想验证栈区究竟是开口向上还是开口向下,都进行先压变量a再压变量b的操作,若a的首地址比b的首地址大则说明开口向下,若b的首地址比a的首地址大,则说明开口向上,下面就用代码来验证一下:

    #include"stdio.h"
    #include"stdlib.h"
    
    int main() {
        int a;
        int b;
        printf("&a : %d\n", &a);
        printf("&b : %d\n", &b);
        system("pause");
        return 0;
    }

    debug下的输出结果:

    这里写图片描述

    release下的输出结果:

    这里写图片描述

    可以看到两个版本下,a的首地址始终比b的首地址大,基本可以判定栈区的开口向下的,有的人的release版本可能会出现a的首地址始终比b的首地址小的情况,其实这个也无关要紧。

    栈区开口向下主要便于避免栈溢出的问题,定义一个开始的最大值,然后开口向下压栈,直到0就不能压栈了。

    二、堆区的地址增长方向

    #include"stdio.h"
    #include"stdlib.h"
    
    int main() {
        int *a= (int*)malloc(10);
        int *b = (int*)malloc(10);
        printf("a : %d\n", a);
        printf("b : %d\n", b);
        system("pause");
        return 0;
    }

    输出结果:

    这里写图片描述

    可以看到堆区是开口向上。

    三、buf地址的增长方向

    这里写图片描述

    不管栈区的开口方向如何,对于栈空间中的buf地址的增长方向都是向上的,如果增长方向向下,对buf首地址+1时岂不是跑到其他内存空间去了。

    三、小结

    1、栈区开口向下(一般情况);

    2、堆区开口向上;’

    3、栈区的地址增长方向与buf地址的增长方向是两个完全不同的概念。

    展开全文
  • 作者:RednaxelaFX ...来源:知乎 ...进程地址空间分布取决于操作系统,向什么方向增长取决于操作系统与CPU组合。 不要把别操作系统实现方式套用到Windows上。 x86硬件直接支持的栈确实...

    作者:RednaxelaFX
    链接:https://www.zhihu.com/question/36103513/answer/66101372
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     

    进程地址空间的分布取决于操作系统,栈向什么方向增长取决于操作系统与CPU的组合。
    不要把别的操作系统的实现方式套用到Windows上。

    x86硬件直接支持的栈确实是“向下增长”的:push指令导致sp自减一个slot,pop指令导致sp自增一个slot。其它硬件有其它硬件的情况。

    ==========================================

    栈的增长方向与栈帧布局

    这个上下文里说的“栈”是函数调用栈,是以“栈帧”(stack frame)为单位的。
    每一次函数调用会在栈上分配一个新的栈帧,在这次函数调用结束时释放其空间。
    被调用函数(callee)的栈帧相对调用函数(caller)的栈帧的位置反映了栈的增长方向:如果被调用函数的栈帧比调用函数的在更低的地址,那么栈就是向下增长;反之则是向上增长。

    而在一个栈帧内,局部变量是如何分布到栈帧里的(所谓栈帧布局,stack frame layout),这完全是编译器的自由。
    至于数组元素与栈的增长方向:C与C++语言规范都规定了数组元素是分布在连续递增的地址上的。引用C语言规范的规定:

    An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.
    A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

    其实double a0[4]这个声明告诉编译器的是:我需要在栈帧里分配一块连续的空间,大小为sizeof(double)*4,并且让a0引用该空间的起始位置(最低地址);
    而不是说:我要根据栈的增长方向,先分配a0[0],然后分配a0[1],再分配a0[2],最后分配a0[3],于是如果栈是向下增长那a0[1]就应该比a0[0]在更低的地址——不是这样的。

    所以在题主给的例子里,a0和a1这两个分配在栈帧里的数组到底哪个在高地址哪个在低地址,其实并不反映栈的增长方向,而只反映了编译器自己的决定。
    C与C++语言的数组元素要分配在连续递增的地址上,也不反映栈的增长方向。

    ==========================================

    以简化的Linux/x86模型为例

    在简化的32位Linux/x86进程地址空间模型里,(主线程的)栈空间确实比堆空间的地址要高——它已经占据了用户态地址空间的最高可分配的区域,并且向下(向低地址)增长。借用Gustavo Duarte的Anatomy of a Program in Memory里的图:


    不过要留意的是这个图是简化模型。举两个例子:

    • 虽然传统上Linux上的malloc实现会使用brk()/sbrk()来实现malloc()(这俩构成了上图中“Heap”所示的部分,这也是Linux自身所认为是heap的地方——用pmap看可以看到这里被标记为[heap]),但这并不是必须的——一个malloc()实现完全可以只用或基本上只用mmap()来实现malloc(),此时一般说的“Heap”(malloc-heap)就不一定在上图“Heap”(Linux heap)所示部分,而会在“Memory Mapping Segment”部分散布开来。不同版本的Linux在分配未指定起始地址的mmap()时用的顺序不一样,并不保证某种顺序。而且mmap()分配到的空间是有可能出现在低于主可执行程序映射进来的text Segment所在的位置。
    • Linux上多线程进程中,“线程”其实是一组共享虚拟地址空间的进程。只有主线程的栈是按照上面图示分布,其它线程的栈的位置其实是“随机”的——它们可以由pthread_create()调用mmap()来分配,也可以由程序自己调用mmap()之后把地址传给pthread_create()。既然是mmap()来的,其它线程的栈出现在Memory Mapping Segment的任意位置都不出奇,与用于实现malloc()用的mmap()空间很可能是交错出现的。

     

    ==========================================

    Windows的进程地址空间

    然而题主的实验是在Windows上而不是在Linux上做的,从截图看起来至少是Windows 7?
    Windows的进程地址空间分布跟上面说的简化的Linux/x86模型颇不一样。
    就算在没有ASLR的老Windows上也已经很不一样,有了ASLR之后就更加不一样了。

    在Windows上不应该对栈和堆的相对位置做任何假设。
    要想看个清楚Windows的进程地址空间长啥样,可以用Sysinternals出品的VMMap看看。该工具简介请见:VMMap - A Peek Inside Virtual Memory

    展开全文
  • 证明栈的开口方向,buf的地址增长方向

    证明栈的开口方向:
    1、定义两个变量(先定义的先入栈)
    2、b的地址小–>开口向下
    b的地址大–>开口向上
    这里写图片描述

    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    
    //栈的开口向上向下,测试 release 和 debug 结果不一样
    //一搬认为:栈开口向下。
    
    //不管栈的开口向上还是向下,定义的 buf 的内存地址 buf+1 永远是向上的
    //栈的生长方向,和buf的内存增长方向是两个不同的概念。
    void main()
    {
        int a;
        int b;
    
        char buf[128];  //buf是静态编译。 即在静态编译的时候,buf所代表的内存编号就已经定下来了
        printf("&a:%d , &b:%d\n",&a,&b);
        system("pause");
    
    }
    展开全文
  • 也是我们编程时经常用到数据结构,在计算机组成原理中,竟然会提到栈地址增长方向与内存地址增长方向相反,那这是为什么呢? 当我们定义一个时,我们事先是不可预料最终大小,因为我们总是会根据需要向...

    我们知道,计算机内存地址增长的方向是自小到大,这很容易理解,也符合我们的常识。

    栈也是我们编程时经常用到的数据结构,在计算机组成原理中,经常会提到栈地址增长方向与内存地址增长方向相反,那这是为什么呢?

    当我们定义一个栈时,我们事先是不可预料栈最终的大小的,因为我们总是会根据需要向栈中添加数据。那么在计算机设计中,若我们将栈也设计为从低地址到高地址增长会是什么样呢?
    在这里插入图片描述
    假设当我们初始化时,我们在地址为0001H的地方开辟了一个栈,那么当我们一次向栈中压入数据时,可以看到地址是依次递增的,假若内存空间最大只到0005H,那么当我们存入第六个数时,地址会增长到0006H,但这个地址已经超出了我们主存的地址空间范围,这就是常说的溢出,这是一件很可怕的事情,因此,为了避免主存出现溢出,栈在设计时就采用了开口朝下的方式:
    在这里插入图片描述
    显然,这么设计是合理的,若栈顶指针SP指向了内存的最小值,我们是很容易捕捉到这种情形的。

    展开全文
  • 栈的增长方向

    2013-12-22 19:46:34
    栈的增长方向 Tag:向下走 栈 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://www.blogbus.com/dreamhead-logs/4840895.html 如何判断栈的增长方向? 对于一个用惯了i386系列...
  • 大家可能都知道,i386系列机器的栈增长方向都是由高地址向低地址方向增长的,也就是说,先入栈的变量地址要高于后入栈的变量的地址,那么对于任何系列的机器如何判断其栈的增长方向呢,这里我将用一段简单的C程序来...
  • 我们在日常开发中,肯定对这个概念很熟悉,C/C++编译器中会把所用局部变量都压入栈中,用完便会自动释放;那么有没有想过它是开口向上(A图)还是开口向下(B图)呢?我们知道它有一个特性,那就是先进后出,...
  • 判断栈的增长方向

    2014-05-16 16:32:51
    如何判断栈的增长方向? 对于一个用惯了i386系列机器的人来说,这似乎是一个无聊的问题,因为栈就是从高地址向低地址增长。不过,显然这不是这个问题的目的,既然把这个问题拿出来,问的就不只是i386系列的机器,...
  • 栈的增长方向(ZZ)

    2019-10-07 12:17:18
    此文是thoughtworks的资深软件工程师原创的,转载并强烈...如何判断栈的增长方向?对于一个用惯了i386系列机器的人来说,这似乎是一个无聊的问题,因为栈就是从高地址向低地址增长。不过,显然这不是这个问题的目的...
  • 空间增长方向

    千次阅读 2013-10-24 21:24:41
    在内存管理中,与栈对应是堆。对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方式是向下的,是向着内存地址减小的方向增长。...在常见的x86中内存中栈的增长方向就是从高地址
  • 如何判断栈的增长方向?对于一个用惯了i386系列机器的人来说,这似乎是一个无聊的问题,因为栈就是从高地址向低地址增长。不过,显然这不是这个问题的目的,既然把这个问题拿出来,问的就不只是i386系列的机器,跨...
  • 处理器栈的增长方向是与具体的处理器有关,首先要明白,栈区是用来存储局部变量、函数参数的区域,其操作上类似于数据结构中的栈,涉及的是变量间的先后入栈,其地址是升序还是降序的问题。 大小端则指的是变量内部...
  • 对于栈这种数据结构,大家应该不会陌生,它是一种后进先出的数据结构。在一般的计算机系统中,栈存在着两种存放数据的方式,...图1 栈的两种增长方向 在图1的(a)中,栈是向上增长的,即数据A对应的地址小于数据B对...
  • 如何判断、堆的增长方向

    万次阅读 多人点赞 2016-07-06 15:35:12
    如何判断栈的增长方向? 对于一个用惯了i386系列机器的人来说,这似乎是一个无聊的问题,因为栈就是从高地址向低地址增长。不过,显然这不是这个问题的目的,既然把这个问题拿出来,问的就不只是i386系列的机器,跨...
  • 此文是thoughtworks的资深软件工程师原创的,转载并强烈推荐他的个人博客。...如何判断栈的增长方向? 对于一个用惯了i386系列机器的人来说,这似乎是一个无聊的问题,因为栈就是从高地址向低地址增长
  • 判断栈增长方向

    2014-12-15 20:13:46
    在内存管理中,与栈对应是堆。对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方式是向下的,是向着内存地址减小的方向增长。...在常见的x86中内存中栈的增长方向就是从高地址
  • 解释:过程中使用了递归,在第一次addr指向的是dummy变量的地址,递归时,会将dummy压栈,第二次的时候dummy的地址也会在里面,这时候比较前后两次压栈的地址,就能够知道中地址的增长方向是向上还是向下。...
  • 等一下,怎么比较两个变量的地址呢?“先声明的先入栈 那就函数加个参数,比较参数和局部变量的位置,参数肯定先入栈。那为什么不能局部变量先入栈?第一反应是怎么可能,但仔细想来又没有什么不可以。所以,这种...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 257
精华内容 102
关键字:

栈的地址增长方向