Why do subsequent Rust variables increment the stack pointer instead of decrementing it?

这一生的挚爱 提交于 2020-01-04 15:53:49

问题


I find it odd how when you create statically-allocated variables in Rust that it seems as the stack pointer increases. I know this is not the case since the stack pointer decreases as memory is allocated.

If I were to do the same thing in C, I would see the stack pointer decrease as I created more variables.

Why is it this way? Does the Rust compiler allocate these from bottom to top instead on top to bottom?

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);
}

When i run this program, I receive this:

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

If I used C, I would get this:

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

回答1:


Think of the stack as a sequence of function stack frames, not a sequence of variable addresses. Regardless of the direction that the stack grows, it grows in increments of whole stack frames, which are different sizes for each function.

The layout of a function's stack frame has fixed positions for where variables will be bound, similar to a struct, but the exact order of bindings within the frame is not guaranteed. If the function can be made to use space more efficiently with a different layout, it probably will. For example:

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

Here, i3 is stored before i2. An i64 needs to be aligned to a multiple of 64 bits so it is more compact to store the two i32s together rather than leaving a gap. This doesn't happen in debug builds, and the compiler could also have chosen to store i3 first with the same effect, so we cannot and should not rely on this ordering.

It's also possible that variables could be reordered for any other optimisation reasons, such as cache access efficiency.


To see that the stack does actually grow downwards, consider an example with multiple functions:

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

another is called by main so its stack frame has a lower address. Notice that I had to force the compiler not to inline the function, otherwise the combined layout would have been arbitrary.



来源:https://stackoverflow.com/questions/54395558/why-do-subsequent-rust-variables-increment-the-stack-pointer-instead-of-decremen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!