2015-06-14 127 views
1

時,我有一個簡單的例子鏽的行爲不符合我的精神形象,所以我想知道我缺少什麼:堆棧行爲返回一個指針到局部變量

fn make_local_int_ptr() -> *const i32 { 
    let a = 3; 
    &a 
} 

fn main() { 
    let my_ptr = make_local_int_ptr(); 
    println!("{}", unsafe { *my_ptr }); 
} 

結果:

3 

這不是我所期望的。使用The Stack and the Heap

給出的符號我希望堆棧幀看起來像這樣:

Address | Name | Value 
----------------------- 
    0 | a | 3 

make_local_int_ptr(),但此行之後,

let my_ptr = make_local_int_ptr(); 

由於a超出範圍,我期望堆棧被清除。但它顯然沒有。

而且,如果我定義創建my_ptr並打印了它的提領值之間的另一個變量:

fn main() { 
    let my_ptr = make_local_int_ptr(); 
    let b = 6; 
    println!("{}", b); // We have to use b otherwise Rust 
         // compiler ignores it (I think) 
    println!("{}", unsafe { *my_ptr }); 
} 

我的輸出是:

6 
0 

這又不是我所期待的,我是思考:

Address | Name | Value 
----------------------- 
    0 | b | 6 

在這種情況下,我的輸出將是:

6 
6 

,甚至(在C++Go我得到這樣的結果):

Address | Name | Value 
----------------------- 
    1 | b | 6 
    0 | a | 3 

在這種情況下,我的輸出是:

6 
3 

但爲什麼我收到的輸出我正在接受?

此外,爲什麼返回一個指向本地變量的指針甚至允許?該變量超出範圍,並且指針指向的值變得不可預知。

+0

當一個函數有許多局部變量時,通常當函數開始時它們會一次性全部分配。因此,在調用'make_local_int_ptr'時,已經分配了'b'(即使它還不可用),所以'a'和'b'不會重疊。 –

+5

[您租用酒店房間。你把書放在最上面的抽屜裏。你第二天早上退房,但「忘記」放棄你的鑰匙。一個星期後,你回到酒店,不要登記入住,用偷來的鑰匙偷偷摸進你的舊房間,然後看着抽屜。你的書還在那裏。驚人(http://stackoverflow.com/a/6445794/395760) – delnan

+0

@delnan:即使到了現在,我只是喜歡這樣的解釋:) –

回答

7

根本不應該返回一個指向本地堆棧變量的指針。這樣做是未定義的行爲,編譯器完全可以自由地執行任何想要的操作。

當您說unsafe時,您承諾編譯器會手動維護所有預期的不變量,然後立即違反該承諾。

說穿了:你違反記憶安全,所有投注都關閉。解決的辦法是不是那樣做。


要解釋爲什麼你可能然而看到這種行爲,(再次,這是不確定的行爲,任何保證):在某種意義上說,它的覆蓋與堆棧不是「清除」零;它再也無法讀取它了。

而且,因爲make_local_int_ptr通話結束時,編譯器沒有理由保存它的堆棧空間,所以它可以重複使用的空間任何東西。由於致電println!0可能是