为什么堆栈和堆都增长?

jfx*_*fxu 1 c memory

我写了这样的代码

int a = 0;
int b = 0;
int *m = (int *)malloc(2* sizeof(int));

printf("%x, %x\n", &a, &b);
printf("%x, %x", &m[0], &m[1]);
Run Code Online (Sandbox Code Playgroud)

得到结果:

46372e18, 46372e1c
d062ec20, d062ec24
Run Code Online (Sandbox Code Playgroud)

这不是堆栈增长和堆积?

zwo*_*wol 8

要了解" 1 "堆栈2的增长方式,必须至少进行一次函数调用.像这样的东西,例如:

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

static ptrdiff_t
stack_probe(uintptr_t stack_addr_from_main)
{
    int var;
    uintptr_t stack_addr_from_me = (uintptr_t)&var;

    return ((intptr_t) stack_addr_from_me) - 
           ((intptr_t) stack_addr_from_main);
}

int
main(void)
{
    int var;
    uintptr_t stack_addr_from_main = (uintptr_t)&var;
    ptrdiff_t stack_delta = stack_probe(stack_addr_from_main);
    printf("Stack offset from one function call = %td\n", stack_delta);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

你必须做,这样一来,因为大多数编译器分配所有的堆栈空间的函数调用一次全部,入境时,在什么叫做"栈帧",并在他们认为合适的组织空间.因此,比较同一函数的两个局部变量的地址并不能告诉你任何有用的东西.您还必须注意编译此程序并关闭"内联"; 如果编译器允许合并stack_probemain,那么它都将再次成为一个堆栈帧,其结果将是没有意义的.(有些编译器允许你逐个函数地控制内联,但据我所知,没有标准的方法可以做到这一点.)

该程序打印的数字由C标准3 "未指定" (表示"它将打印一些数字,但标准不要求它是任何特定的数字").但是,几乎所有计算机上你都可能会在今天开始使用它,它会打印一个负数,这意味着堆栈会向下增长.如果您设法在运行HP-UX的PA-RISC计算机上运行它(它可能甚至不能编译,不幸的是;我不记得HP-UX是否曾经拥有符合C99标准的库)它将打印一个正数,并且这意味着堆栈向上增长.

一些计算机,这个程序打印的数字不会有任何意义,因为它们相当于"堆栈"不一定是连续的内存块.查找最简单版本的"拆分堆栈".

顺便说一句,"堆"不一定会成长下降.连续调用malloc返回指针,彼此之间没有任何有意义的关系,总是如此.


1可以有多个堆栈,例如在使用线程时.

2有趣的事实:"堆栈"这个词在C标准中没有出现.需要支持递归函数调用,但实现如何管理完全取决于实现.

3此外,该程序是否将编译是实现定义的,因为不需要提供intptr_t和实现uintptr_t.但是,如果我没有使用这些类型,程序将有未定义的行为("它允许做任何事情,包括崩溃并删除所有代码"),因为你只允许采取两个指针的差异当他们指向同一个数组时,这些不是.