Pointers 为什么后续的Rust变量会增加堆栈指针而不是减少它?

Pointers 为什么后续的Rust变量会增加堆栈指针而不是减少它?,pointers,memory,rust,stack,allocation,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); prin

我发现奇怪的是,当您在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
将堆栈视为函数堆栈帧序列,而不是变量地址序列。无论堆栈的增长方向如何,它都以整个堆栈帧的增量增长,每个函数的大小都不同

函数堆栈框架的布局有固定的变量绑定位置,类似于结构,但框架内绑定的确切顺序无法保证。如果功能可以通过不同的布局更有效地利用空间,它可能会。例如:

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

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

例如,如果我使用C,我会得到这个结果-你确定吗?并不是说标准中规定了这样的事情,而是,例如,我得到了一个随后声明的变量的递增地址,就像在您的rust示例中一样。相关:局部变量在单个堆栈帧中分配的顺序与堆栈增长的方向无关。后者是由ABI和平台强制执行的,前者在函数调用边界是不可见的,每个编译器可以选择它喜欢的顺序。我不认为您观察的顺序是由Rust编译器强制执行的——它可能是由LLVM定义的。欢迎使用实现行为,而且C标准甚至没有提到单词堆栈。