我在第2章关于"Stack and Heap"的Ivo Balbaert书中找到了Rust Essentials一书中变量的内存位置代码:
let a = 32;
let mut b = "str";
println!({:p} {:p}, &a, &b);
该书的输出为 0x23fba4 0x23fb90
,它表明第一个地址是堆栈中的位置,第二个地址是堆中的位置 .
我对这个陈述有些怀疑,因为我听说堆栈地址越来越大,内存地址越来越少 . 上面的第二个地址似乎是堆栈中的一个位置 .
我错了吗?
引用:
现在,我们将运行以下程序并尝试可视化程序的内存://参见第2章/ code / references.rs让health = 32;
让mut game =“太空侵略者”;
值存储在内存中,因此它们具有内存地址 . 运行状况变量包含一个整数值32,它存储在位于0x23fba4的堆栈中,而变量游戏包含一个字符串,该字符串存储在从位置0x23fb90开始的堆中 . (这些是我执行程序时的地址,但是在运行程序时它们会有所不同 . )绑定值的变量是指针或对值的引用 . 他们指向他们;游戏是对太空入侵者的参考 . 值的地址由&运算符给出 . 因此,&health是存储值32的地址,&game是存储Space Invaders值的地址 . 我们可以使用格式字符串{:p}来打印这些地址,如下所示:println!(“address of health-value:{:p}”,&health); //打印0x23fba4
println!(“游戏 Value 地址:{:p}”,&game); //打印0x23fb90
1 回答
作为user4815162342 commented,这本书是错误的 . 作为变量
b
的胖指针位于堆栈上,就像a
一样 . 只有它指向的字符串数据才能在其他地方 .在示例
let mut b = "str";
中,字符串数据实际上不在堆附近 . 它静态地放在程序的data segment中 . 要真正将它放在堆上,我们需要使用let b = String::from("str");
. 生成的内存将如下图所示:让我们手动检查内存,看看发生了什么 .
假设
a
和b
位于地址0x7ffeda6df61c和0x7ffeda6df620 .输出看起来像这样:
[32, 0, 0, 0, 128, 85, 251, 177, 191, 85, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0]
32, 0, 0, 0
:a
的四个字节128, 85, 251, 177, 191, 85, 0, 0
:b
的第一部分,64位指向字符串数据的指针3, 0, 0, 0, 0, 0, 0, 0
:b
的第二部分,字符串的长度现在按照数据指针:
虽然
a
和b
位于相同的内存区域(0x7f ...),但字符串数据位于不同的区域(0x7e ...) .前三个字节包含s,t和r的ASCII代码 . 第四个字节是任意垃圾 .
以下是完整的代码 .
请注意,代码示例假设64位指针并依赖于编译器的实现细节,并且可能在将来或其他系统上中断 . 特别是,不保证堆栈帧或
&str
的布局 . 请不要在实际代码中使用任何这些:)