pointers - 为什么后续的 Rust 变量会递增堆栈指针而不是递减它?

标签 pointers memory rust stack allocation

我发现很奇怪的是,当你在 Rust 中创建静态分配的变量时,它似乎随着堆栈指针的增加而增加。我知道情况并非如此,因为堆栈指针随着内存分配而减少。

如果我在 C 中做同样的事情,我会看到堆栈指针随着我创建更多变量而减少。

为什么会这样? Rust 编译器是否从下到上而不是从上到下分配它们?

fn main() {
    let i1 = 1;
    let i2 = 1;
    let i3 = 1;
    println!("i1 : {:?}", &i1 as *const i32);
    println!("i2 : {:?}", &i2 as *const i32);
    println!("i3 : {:?}", &i3 as *const i32);
}

当我运行这个程序时,我收到:

i1 : 0x9f4f99fb24
i2 : 0x9f4f99fb28
i3 : 0x9f4f99fb2c

如果我使用 C,我会得到这个:

i1 : 0x9f4f99fb2c
i2 : 0x9f4f99fb28
i3 : 0x9f4f99fb24

最佳答案

将堆栈视为函数堆栈帧的序列,而不是变量地址的序列。无论堆栈向哪个方向增长,它都会以整个堆栈帧的增量增长,每个函数的堆栈帧大小不同。

函数堆栈帧的布局对于绑定(bind)变量有固定的位置,类似于结构体,但不能保证帧内绑定(bind)的确切顺序。如果可以通过不同的布局使该功能更有效地利用空间,那么它可能会实现。例如:

fn main() {
    let i1: i32 = 1;
    let i2: i64 = 2;
    let i3: i32 = 3;
    println!("i1 : {:?}", &i1 as *const i32);
    println!("i2 : {:?}", &i2 as *const i64);
    println!("i3 : {:?}", &i3 as *const i32);
}

// i1 : 0x7fff4b9271fc
// i2 : 0x7fff4b927200
// i3 : 0x7fff4b92720c

这里,i3存储在i2之前。 i64 需要与 64 位的倍数对齐,因此将两个 i32 存储在一起而不是留下间隙会更加紧凑。这种情况在调试版本中不会发生,并且编译器也可以选择首先存储 i3 以获得相同的效果,因此我们不能也不应该依赖此顺序。

也可能出于任何其他优化原因(例如缓存访问效率)对变量重新排序。


要查看堆栈实际上是向下增长的,请考虑一个具有多个函数的示例:

fn main() {
    let i1 = 1;
    println!("i1 : {:?}", &i1 as *const i32);

    another();
}

#[inline(never)]
fn another() {
    let i2 = 2;
    println!("i2 : {:?}", &i2 as *const i32);
}

// i1 : 0x7fffc7601fbc
// i2 : 0x7fffc7601f5c

anothermain 调用,因此其堆栈帧具有较低的地址。请注意,我必须强制编译器不要内联该函数,否则组合布局将是任意的。

关于pointers - 为什么后续的 Rust 变量会递增堆栈指针而不是递减它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54395558/

相关文章:

c++ - 线程内存问题(tinythread,C++)

rust - 在 Rust 中的多个向量中有一个结构实例

rust - 如何在 Rust 中迭代宏的参数?

ruby-on-rails - Ruby 和 PostgreSQL 单行模式

rust - 将模式作为函数参数传递?

c - 二维数组和指针

c++ - 指向字符串和字符的指针捕获 22

在C中复制字符串数组

c - 指向自身的整数数组的起始地址?

c - 取消引用自定义内存地址时出现段错误 (C)